v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
liftoff-assembler-arm64-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_ARM64_LIFTOFF_ASSEMBLER_ARM64_INL_H_
6#define V8_WASM_BASELINE_ARM64_LIFTOFF_ASSEMBLER_ARM64_INL_H_
7
17
18namespace v8::internal::wasm {
19
20namespace liftoff {
21
22// Liftoff Frames.
23//
24// slot Frame
25// +--------------------+---------------------------
26// n+4 | optional padding slot to keep the stack 16 byte aligned.
27// n+3 | parameter n |
28// ... | ... |
29// 4 | parameter 1 | or parameter 2
30// 3 | parameter 0 | or parameter 1
31// 2 | (result address) | or parameter 0
32// -----+--------------------+---------------------------
33// 1 | return addr (lr) |
34// 0 | previous frame (fp)|
35// -----+--------------------+ <-- frame ptr (fp)
36// -1 | StackFrame::WASM |
37// -2 | instance |
38// -3 | feedback vector|
39// -----+--------------------+---------------------------
40// -4 | slot 0 | ^
41// -5 | slot 1 | |
42// | | Frame slots
43// | | |
44// | | v
45// | optional padding slot to keep the stack 16 byte aligned.
46// -----+--------------------+ <-- stack ptr (sp)
47//
48
49inline MemOperand GetStackSlot(int offset) { return MemOperand(fp, -offset); }
50
53}
54
56 switch (kind) {
57 case kI32:
58 return reg.gp().W();
59 case kI64:
60 case kRef:
61 case kRefNull:
62 return reg.gp().X();
63 case kF32:
64 return reg.fp().S();
65 case kF64:
66 return reg.fp().D();
67 case kS128:
68 return reg.fp().Q();
69 default:
71 }
72}
73
75 if ((list.Count() & 1) != 0) list.set(padreg);
76 return CPURegList(kXRegSizeInBits, list);
77}
78
80 if ((list.Count() & 1) != 0) list.set(fp_scratch);
81 return CPURegList(kQRegSizeInBits, list);
82}
83
86 switch (kind) {
87 case kI32:
88 return temps->AcquireW();
89 case kI64:
90 case kRef:
91 case kRefNull:
92 return temps->AcquireX();
93 case kF32:
94 return temps->AcquireS();
95 case kF64:
96 return temps->AcquireD();
97 case kS128:
98 return temps->AcquireQ();
99 default:
100 UNREACHABLE();
101 }
102}
103
104template <typename T>
107 Register offset, T offset_imm,
108 bool i64_offset = false, unsigned shift_amount = 0) {
109 if (!offset.is_valid()) return MemOperand(addr.X(), offset_imm);
110 Register effective_addr = addr.X();
111 if (offset_imm) {
112 effective_addr = temps->AcquireX();
113 assm->Add(effective_addr, addr.X(), offset_imm);
114 }
115 return i64_offset
116 ? MemOperand(effective_addr, offset.X(), LSL, shift_amount)
117 : MemOperand(effective_addr, offset.W(), UXTW, shift_amount);
118}
119
120// Compute the effective address (sum of |addr|, |offset| (if given) and
121// |offset_imm|) into a temporary register. This is needed for certain load
122// instructions that do not support an offset (register or immediate).
123// Returns |addr| if both |offset| and |offset_imm| are zero.
127 uintptr_t offset_imm,
128 bool i64_offset = false) {
129 if (!offset.is_valid() && offset_imm == 0) return addr;
130 Register tmp = temps->AcquireX();
131 if (offset.is_valid()) {
132 assm->Add(tmp, addr, i64_offset ? Operand(offset) : Operand(offset, UXTW));
133 addr = tmp;
134 }
135 if (offset_imm != 0) assm->Add(tmp, addr, offset_imm);
136 return tmp;
137}
138
139enum class ShiftDirection : bool { kLeft, kRight };
140
141enum class ShiftSign : bool { kSigned, kUnsigned };
142
143template <ShiftDirection dir, ShiftSign sign = ShiftSign::kSigned>
145 Register rhs, VectorFormat format) {
147 DCHECK(dst.IsSameFormat(lhs));
149
150 UseScratchRegisterScope temps(assm);
151 VRegister tmp = temps.AcquireV(format);
152 Register shift = dst.Is2D() ? temps.AcquireX() : temps.AcquireW();
153 int mask = LaneSizeInBitsFromFormat(format) - 1;
154 assm->And(shift, rhs, mask);
155 assm->Dup(tmp, shift);
156
157 if (dir == ShiftDirection::kRight) {
158 assm->Neg(tmp, tmp);
159 }
160
161 if (sign == ShiftSign::kSigned) {
162 assm->Sshl(dst, lhs, tmp);
163 } else {
164 assm->Ushl(dst, lhs, tmp);
165 }
166}
167
168template <VectorFormat format, ShiftSign sign>
170 VRegister lhs, int32_t rhs) {
171 // Sshr and Ushr does not allow shifts to be 0, so check for that here.
172 int mask = LaneSizeInBitsFromFormat(format) - 1;
173 int32_t shift = rhs & mask;
174 if (!shift) {
175 if (dst != lhs) {
176 assm->Mov(dst, lhs);
177 }
178 return;
179 }
180
181 if (sign == ShiftSign::kSigned) {
182 assm->Sshr(dst, lhs, rhs & mask);
183 } else {
184 assm->Ushr(dst, lhs, rhs & mask);
185 }
186}
187
188inline void EmitAnyTrue(LiftoffAssembler* assm, LiftoffRegister dst,
189 LiftoffRegister src) {
190 // AnyTrue does not depend on the number of lanes, so we can use V4S for all.
191 UseScratchRegisterScope scope(assm);
192 VRegister temp = scope.AcquireV(kFormat4S);
193 assm->Umaxp(temp, src.fp().V4S(), src.fp().V4S());
194 assm->Fmov(dst.gp().X(), temp.D());
195 assm->Cmp(dst.gp().X(), 0);
196 assm->Cset(dst.gp().W(), ne);
197}
198
200 LiftoffRegister src, VectorFormat format) {
201 UseScratchRegisterScope scope(assm);
202 VRegister temp = scope.AcquireV(ScalarFormatFromFormat(format));
203 assm->Uminv(temp, VRegister::Create(src.fp().code(), format));
204 assm->Umov(dst.gp().W(), temp, 0);
205 assm->Cmp(dst.gp().W(), 0);
206 assm->Cset(dst.gp().W(), ne);
207}
208
211 const LiftoffAssembler::VarState& src) {
212 if (src.is_reg()) {
213 return GetRegFromType(src.reg(), src.kind());
214 }
215 if (src.is_const()) {
216 if (src.kind() == kI32) {
217 if (src.i32_const() == 0) return wzr;
218 Register temp = temps->AcquireW();
219 assm->Mov(temp, src.i32_const());
220 return temp;
221 }
222 DCHECK_EQ(kI64, src.kind());
223 if (src.i32_const() == 0) return xzr;
224 Register temp = temps->AcquireX();
225 assm->Mov(temp, static_cast<int64_t>(src.i32_const()));
226 return temp;
227 }
228 DCHECK(src.is_stack());
229 CPURegister temp = AcquireByType(temps, src.kind());
230 assm->Ldr(temp, GetStackSlot(src.offset()));
231 return temp;
232}
233
235 const LiftoffAssembler::VarState& src) {
236 if (src.kind() == kI16) {
237 DCHECK(src.is_reg());
238 assm->Strh(src.reg().gp(), dst);
239 return;
240 }
241 UseScratchRegisterScope temps{assm};
242 CPURegister src_reg = LoadToRegister(assm, &temps, src);
243 assm->Str(src_reg, dst);
244}
245
246} // namespace liftoff
247
249 int offset = pc_offset();
250 InstructionAccurateScope scope(this, 1);
251 // Next we reserve the memory for the whole stack frame. We do not know yet
252 // how big the stack frame will be so we just emit a placeholder instruction.
253 // PatchPrepareStackFrame will patch this in order to increase the stack
254 // appropriately.
255 sub(sp, sp, 0);
256 return offset;
257}
258
260// The standard library used by gcc tryjobs does not consider `std::find` to be
261// `constexpr`, so wrap it in a `#ifdef __clang__` block.
262#ifdef __clang__
263 static_assert(std::find(std::begin(wasm::kGpParamRegisters),
264 std::end(wasm::kGpParamRegisters),
265 kLiftoffFrameSetupFunctionReg) ==
266 std::end(wasm::kGpParamRegisters));
267#endif
268
269 // On ARM64, we must push at least {lr} before calling the stub, otherwise
270 // it would get clobbered with no possibility to recover it. So just set
271 // up the frame here.
272 EnterFrame(StackFrame::WASM);
273 LoadConstant(LiftoffRegister(kLiftoffFrameSetupFunctionReg),
274 WasmValue(declared_function_index));
275 CallBuiltin(Builtin::kWasmLiftoffFrameSetup);
276}
277
278void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params,
279 int stack_param_delta) {
280 UseScratchRegisterScope temps(this);
281 temps.Exclude(x16, x17);
282
283 // This is the previous stack pointer value (before we push the lr and the
284 // fp). We need to keep it to autenticate the lr and adjust the new stack
285 // pointer afterwards.
286 Add(x16, fp, 16);
287
288 // Load the fp and lr of the old frame, they will be pushed in the new frame
289 // during the actual call.
290#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
291 Ldp(fp, x17, MemOperand(fp));
292 Autib1716();
293 Mov(lr, x17);
294#else
295 Ldp(fp, lr, MemOperand(fp));
296#endif
297
298 temps.Include(x17);
299
300 Register scratch = temps.AcquireX();
301
302 // Shift the whole frame upwards, except for fp and lr.
303 // Adjust x16 to be the new stack pointer first, so that {str} doesn't need
304 // a temp register to materialize the offset.
305 Sub(x16, x16, stack_param_delta * 8);
306 int slot_count = num_callee_stack_params;
307 for (int i = slot_count - 1; i >= 0; --i) {
308 ldr(scratch, MemOperand(sp, i * 8));
309 str(scratch, MemOperand(x16, i * 8));
310 }
311
312 // Set the new stack pointer.
313 mov(sp, x16);
314}
315
317 // The frame_size includes the frame marker. The frame marker has already been
318 // pushed on the stack though, so we don't need to allocate memory for it
319 // anymore.
320 int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize;
321
322 static_assert(kStackSlotSize == kXRegSize,
323 "kStackSlotSize must equal kXRegSize");
324
325 // The stack pointer is required to be quadword aligned.
326 // Misalignment will cause a stack alignment fault.
327 int misalignment = frame_size % kQuadWordSizeInBytes;
328 if (misalignment) {
329 int padding = kQuadWordSizeInBytes - misalignment;
330 frame_size += padding;
331 max_used_spill_offset_ += padding;
332 }
333}
334
336 int offset, SafepointTableBuilder* safepoint_table_builder,
337 bool feedback_vector_slot, size_t stack_param_slots) {
338 // The frame_size includes the frame marker and the instance slot. Both are
339 // pushed as part of frame construction, so we don't need to allocate memory
340 // for them anymore.
341 int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize;
342 // The frame setup builtin also pushes the feedback vector, and an unused
343 // slot for alignment.
344 if (feedback_vector_slot) {
345 frame_size = std::max(frame_size - 2 * kSystemPointerSize, 0);
346 }
347
348 // The stack pointer is required to be quadword aligned.
349 // Misalignment will cause a stack alignment fault.
350 DCHECK_EQ(frame_size, RoundUp(frame_size, kQuadWordSizeInBytes));
351
352 PatchingAssembler patching_assembler(zone(), AssemblerOptions{},
353 buffer_start_ + offset, 1);
354
355 if (V8_LIKELY(frame_size < 4 * KB)) {
356 // This is the standard case for small frames: just subtract from SP and be
357 // done with it.
358 DCHECK(IsImmAddSub(frame_size));
359 patching_assembler.PatchSubSp(frame_size);
360 return;
361 }
362
363 // The frame size is bigger than 4KB, so we might overflow the available stack
364 // space if we first allocate the frame and then do the stack check (we will
365 // need some remaining stack space for throwing the exception). That's why we
366 // check the available stack space before we allocate the frame. To do this we
367 // replace the {__ sub(sp, sp, framesize)} with a jump to OOL code that does
368 // this "extended stack check".
369 //
370 // The OOL code can simply be generated here with the normal assembler,
371 // because all other code generation, including OOL code, has already finished
372 // when {PatchPrepareStackFrame} is called. The function prologue then jumps
373 // to the current {pc_offset()} to execute the OOL code for allocating the
374 // large frame.
375
376 // Emit the unconditional branch in the function prologue (from {offset} to
377 // {pc_offset()}).
378 patching_assembler.b((pc_offset() - offset) >> kInstrSizeLog2);
379
380 // If the frame is bigger than the stack, we throw the stack overflow
381 // exception unconditionally. Thereby we can avoid the integer overflow
382 // check in the condition code.
383 RecordComment("OOL: stack check for large frame");
384 Label continuation;
385 if (frame_size < v8_flags.stack_size * 1024) {
386 UseScratchRegisterScope temps(this);
387 Register stack_limit = temps.AcquireX();
389 Add(stack_limit, stack_limit, Operand(frame_size));
390 Cmp(sp, stack_limit);
391 B(hs /* higher or same */, &continuation);
392 }
393
394 if (v8_flags.experimental_wasm_growable_stacks) {
395 LiftoffRegList regs_to_save;
397 regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister());
398 for (auto reg : kGpParamRegisters) regs_to_save.set(reg);
399 for (auto reg : kFpParamRegisters) regs_to_save.set(reg);
402 Add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp,
403 Operand(stack_param_slots * kStackSlotSize +
405 CallBuiltin(Builtin::kWasmHandleStackOverflow);
406 safepoint_table_builder->DefineSafepoint(this);
408 } else {
409 Call(static_cast<Address>(Builtin::kWasmStackOverflow),
411 // The call will not return; just define an empty safepoint.
412 safepoint_table_builder->DefineSafepoint(this);
413 if (v8_flags.debug_code) Brk(0);
414 }
415
417
418 // Now allocate the stack space. Note that this might do more than just
419 // decrementing the SP; consult {MacroAssembler::Claim}.
420 Claim(frame_size, 1);
421
422 // Jump back to the start of the function, from {pc_offset()} to
423 // right after the reserved space for the {__ sub(sp, sp, framesize)} (which
424 // is a branch now).
425 int func_start_offset = offset + kInstrSize;
426 b((func_start_offset - pc_offset()) >> kInstrSizeLog2);
427}
428
430
432
433// static
436}
437
439 // TODO(zhin): Unaligned access typically take additional cycles, we should do
440 // some performance testing to see how big an effect it will take.
441 switch (kind) {
442 case kS128:
443 return value_kind_size(kind);
444 default:
445 return kStackSlotSize;
446 }
447}
448
450 return kind == kS128 || is_reference(kind);
451}
452
453void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used,
454 Label* ool_label,
455 const FreezeCacheState& frozen) {
456 UseScratchRegisterScope temps{this};
457 Register budget_array = temps.AcquireX();
458
460 if (instance_data == no_reg) {
461 instance_data = budget_array; // Reuse the temp register.
463 }
464
465 constexpr int kArrayOffset = wasm::ObjectAccess::ToTagged(
466 WasmTrustedInstanceData::kTieringBudgetArrayOffset);
467 ldr(budget_array, MemOperand{instance_data, kArrayOffset});
468
469 int budget_arr_offset = kInt32Size * declared_func_index;
470 // If the offset cannot be used in the operand directly, add it once to the
471 // budget_array to avoid doing that two times below.
472 if (!IsImmLSScaled(budget_arr_offset, 2 /* log2(sizeof(i32)) */) &&
473 !IsImmLSUnscaled(budget_arr_offset)) {
474 Add(budget_array, budget_array, budget_arr_offset);
475 budget_arr_offset = 0;
476 }
477
478 Register budget = temps.AcquireW();
479 MemOperand budget_addr{budget_array, budget_arr_offset};
480 ldr(budget, budget_addr);
481 // Make sure that the {budget_used} can be used as an immediate for SUB.
482 if (budget_used > 0xFFF000) {
483 budget_used = 0xFFF000; // 16'773'120
484 } else if (budget_used > 0xFFF) {
485 budget_used &= 0xFFF000;
486 }
487 DCHECK(IsImmAddSub(budget_used));
488 AddSub(budget, budget, Operand{budget_used}, SetFlags, SUB);
489 str(budget, budget_addr);
490 B(ool_label, mi);
491}
492
494 if (!v8_flags.experimental_wasm_growable_stacks) {
495 return fp;
496 }
497 LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {});
498 Label done, call_runtime;
500 Cmp(old_fp.gp(),
501 Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)));
502 B(eq, &call_runtime);
503 Mov(old_fp.gp(), fp);
504 jmp(&done);
505
506 bind(&call_runtime);
507 LiftoffRegList regs_to_save = cache_state()->used_registers;
510 CallCFunction(ExternalReference::wasm_load_old_fp(), 1);
511 if (old_fp.gp() != kReturnRegister0) {
512 Mov(old_fp.gp(), kReturnRegister0);
513 }
515
516 bind(&done);
517 return old_fp.gp();
518}
519
521 {
522 UseScratchRegisterScope temps{this};
523 Register scratch = temps.AcquireX();
525 Cmp(scratch,
526 Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)));
527 }
528 Label done;
529 B(ne, &done);
530 LiftoffRegList regs_to_save;
531 for (auto reg : kGpReturnRegisters) regs_to_save.set(reg);
532 for (auto reg : kFpReturnRegisters) regs_to_save.set(reg);
535 CallCFunction(ExternalReference::wasm_shrink_stack(), 1);
538 if (options().enable_simulator_code) {
539 // The next instruction after shrinking stack is leaving the frame.
540 // So SP will be set to old FP there. Switch simulator stack limit here.
541 UseScratchRegisterScope temps{this};
542 temps.Exclude(x16);
545 }
546 bind(&done);
547}
548
549void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) {
550 switch (value.type().kind()) {
551 case kI32:
552 Mov(reg.gp().W(), value.to_i32());
553 break;
554 case kI64:
555 Mov(reg.gp().X(), value.to_i64());
556 break;
557 case kF32:
558 Fmov(reg.fp().S(), value.to_f32());
559 break;
560 case kF64:
561 Fmov(reg.fp().D(), value.to_f64());
562 break;
563 default:
564 UNREACHABLE();
565 }
566}
567
570}
571
572void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr,
573 int offset, IndirectPointerTag tag) {
574 MemOperand src{src_addr, offset};
575 LoadTrustedPointerField(dst, src, tag);
576}
577
578void LiftoffAssembler::LoadFromInstance(Register dst, Register instance,
579 int offset, int size) {
580 DCHECK_LE(0, offset);
581 MemOperand src{instance, offset};
582 switch (size) {
583 case 1:
584 Ldrb(dst.W(), src);
585 break;
586 case 4:
587 Ldr(dst.W(), src);
588 break;
589 case 8:
590 Ldr(dst, src);
591 break;
592 default:
594 }
595}
596
598 Register instance,
599 int offset) {
600 DCHECK_LE(0, offset);
601 LoadTaggedField(dst, MemOperand{instance, offset});
602}
603
604void LiftoffAssembler::SpillInstanceData(Register instance) {
605 Str(instance, liftoff::GetInstanceDataOperand());
606}
607
609
610enum class LoadOrStore : bool { kLoad, kStore };
611
612// The purpose of this class is to reconstruct the PC offset of a protected
613// instruction (load or store) that has just been emitted. We cannot simply
614// record the current PC offset before emitting the instruction, because the
615// respective helper function we call might emit more than one instruction
616// (e.g. to load an immediate into a register, or to get a constant pool
617// out of the way).
618//
619// Template arguments:
620// kLoadOrStore:
621// DCHECK that the detected protected instruction has the right type.
622// kExtraEmittedInstructions:
623// By default, we assume that when the destructor runs, the PC is right
624// behind the protected instruction. If additional instructions are expected
625// to have been emitted (such as a pointer decompression), specify their
626// number here.
627template <LoadOrStore kLoadOrStore, uint8_t kExtraEmittedInstructions = 0>
629 public:
631 uint32_t* protected_instruction_pc)
632 : assm_(assm),
633 protected_instruction_pc_(protected_instruction_pc),
634 // First emit any required pools...
636 // ...then record the PC offset before the relevant instruction
637 // sequence.
639
641 if (!protected_instruction_pc_) return;
643 assm_->pc_offset() - kInstrSize * (1 + kExtraEmittedInstructions);
644 if constexpr (kLoadOrStore == LoadOrStore::kLoad) {
645 DCHECK(assm_->InstructionAt(*protected_instruction_pc_)->IsLoad());
646 } else {
647 DCHECK(assm_->InstructionAt(*protected_instruction_pc_)->IsStore());
648 }
649 // Make sure {kReservedInstructions} was large enough.
653 }
654
655 private:
656 // For simplicity, we hard-code this value. We could make it a template
657 // argument if we needed more flexibility. It must be at least the maximum
658 // length of the instruction sequence emitted by the {LoadTaggedField} etc.
659 // helper functions below.
660 static constexpr int kReservedInstructions = 4;
661
666};
667
669 Register offset_reg,
670 int32_t offset_imm,
671 uint32_t* protected_load_pc,
672 bool needs_shift) {
673 UseScratchRegisterScope temps(this);
674 unsigned shift_amount = !needs_shift ? 0 : COMPRESS_POINTERS_BOOL ? 2 : 3;
675 MemOperand src_op = liftoff::GetMemOp(this, &temps, src_addr, offset_reg,
676 offset_imm, false, shift_amount);
677 DCHECK(!src_op.IsPostIndex()); // See MacroAssembler::LoadStoreMacroComplex.
678 constexpr uint8_t kDecompressionInstruction = COMPRESS_POINTERS_BOOL ? 1 : 0;
680 collect_protected_load(this, protected_load_pc);
681 LoadTaggedField(dst, src_op);
682}
683
685 int32_t offset_imm) {
686 LoadProtectedPointerField(dst, MemOperand{src_addr, offset_imm});
687}
688
689void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr,
690 int32_t offset_imm) {
691 UseScratchRegisterScope temps(this);
692 MemOperand src_op =
693 liftoff::GetMemOp(this, &temps, src_addr, no_reg, offset_imm);
694 Ldr(dst.X(), src_op);
695}
696
697#ifdef V8_ENABLE_SANDBOX
698void LiftoffAssembler::LoadCodeEntrypointViaCodePointer(Register dst,
699 Register src_addr,
700 int32_t offset_imm) {
701 UseScratchRegisterScope temps(this);
702 MemOperand src_op =
703 liftoff::GetMemOp(this, &temps, src_addr, no_reg, offset_imm);
704 MacroAssembler::LoadCodeEntrypointViaCodePointer(dst, src_op,
706}
707#endif
708
709void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
710 Register offset_reg,
711 int32_t offset_imm, Register src,
712 LiftoffRegList /* pinned */,
713 uint32_t* protected_store_pc,
714 SkipWriteBarrier skip_write_barrier) {
715 UseScratchRegisterScope temps(this);
716 Operand offset_op = offset_reg.is_valid() ? Operand(offset_reg.W(), UXTW)
717 : Operand(offset_imm);
718 // This is similar to {liftoff::GetMemOp}, but leaves {dst_addr} alone, and
719 // gives us a combined {offset_op}, which we need for the write barrier
720 // below. The 32-bit addition is okay because on-heap offsets don't get
721 // bigger than that.
722 if (offset_reg.is_valid() && offset_imm) {
723 Register effective_offset = temps.AcquireX();
724 Add(effective_offset.W(), offset_reg.W(), offset_imm);
725 offset_op = effective_offset;
726 }
727 {
728 GetProtectedInstruction<LoadOrStore::kStore> collect_protected_store(
729 this, protected_store_pc);
730 StoreTaggedField(src, MemOperand(dst_addr.X(), offset_op));
731 }
732
733 if (skip_write_barrier || v8_flags.disable_write_barriers) return;
734
735 // The write barrier.
736 Label exit;
738 kZero, &exit);
739 JumpIfSmi(src, &exit);
742 StubCallMode::kCallWasmRuntimeStub);
743 bind(&exit);
744}
745
746void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
747 Register offset_reg, uintptr_t offset_imm,
748 LoadType type, uint32_t* protected_load_pc,
749 bool /* is_load_mem */, bool i64_offset,
750 bool needs_shift) {
751 UseScratchRegisterScope temps(this);
752 unsigned shift_amount = needs_shift ? type.size_log_2() : 0;
753 MemOperand src_op = liftoff::GetMemOp(this, &temps, src_addr, offset_reg,
754 offset_imm, i64_offset, shift_amount);
755 DCHECK(!src_op.IsPostIndex()); // See MacroAssembler::LoadStoreMacroComplex.
756 GetProtectedInstruction<LoadOrStore::kLoad> collect_protected_load(
757 this, protected_load_pc);
758 switch (type.value()) {
759 case LoadType::kI32Load8U:
760 case LoadType::kI64Load8U:
761 Ldrb(dst.gp().W(), src_op);
762 break;
763 case LoadType::kI32Load8S:
764 Ldrsb(dst.gp().W(), src_op);
765 break;
766 case LoadType::kI64Load8S:
767 Ldrsb(dst.gp().X(), src_op);
768 break;
769 case LoadType::kI32Load16U:
770 case LoadType::kI64Load16U:
771 Ldrh(dst.gp().W(), src_op);
772 break;
773 case LoadType::kI32Load16S:
774 Ldrsh(dst.gp().W(), src_op);
775 break;
776 case LoadType::kI64Load16S:
777 Ldrsh(dst.gp().X(), src_op);
778 break;
779 case LoadType::kI32Load:
780 case LoadType::kI64Load32U:
781 Ldr(dst.gp().W(), src_op);
782 break;
783 case LoadType::kI64Load32S:
784 Ldrsw(dst.gp().X(), src_op);
785 break;
786 case LoadType::kI64Load:
787 Ldr(dst.gp().X(), src_op);
788 break;
789 case LoadType::kF32Load:
790 Ldr(dst.fp().S(), src_op);
791 break;
792 case LoadType::kF32LoadF16: {
793 CpuFeatureScope scope(this, FP16);
794 Ldr(dst.fp().H(), src_op);
795 Fcvt(dst.fp().S(), dst.fp().H());
796 break;
797 }
798 case LoadType::kF64Load:
799 Ldr(dst.fp().D(), src_op);
800 break;
801 case LoadType::kS128Load:
802 Ldr(dst.fp().Q(), src_op);
803 break;
804 }
805}
806
807void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
808 uintptr_t offset_imm, LiftoffRegister src,
809 StoreType type, LiftoffRegList /* pinned */,
810 uint32_t* protected_store_pc,
811 bool /* is_store_mem */, bool i64_offset) {
812 UseScratchRegisterScope temps(this);
813 MemOperand dst_op = liftoff::GetMemOp(this, &temps, dst_addr, offset_reg,
814 offset_imm, i64_offset);
815 DCHECK(!dst_op.IsPostIndex()); // See MacroAssembler::LoadStoreMacroComplex.
816 GetProtectedInstruction<LoadOrStore::kStore> collect_protected_store(
817 this, protected_store_pc);
818 switch (type.value()) {
819 case StoreType::kI32Store8:
820 case StoreType::kI64Store8:
821 Strb(src.gp().W(), dst_op);
822 break;
823 case StoreType::kI32Store16:
824 case StoreType::kI64Store16:
825 Strh(src.gp().W(), dst_op);
826 break;
827 case StoreType::kI32Store:
828 case StoreType::kI64Store32:
829 Str(src.gp().W(), dst_op);
830 break;
831 case StoreType::kI64Store:
832 Str(src.gp().X(), dst_op);
833 break;
834 case StoreType::kF32StoreF16: {
835 CpuFeatureScope scope(this, FP16);
836 Fcvt(src.fp().H(), src.fp().S());
837 Str(src.fp().H(), dst_op);
838 break;
839 }
840 case StoreType::kF32Store:
841 Str(src.fp().S(), dst_op);
842 break;
843 case StoreType::kF64Store:
844 Str(src.fp().D(), dst_op);
845 break;
846 case StoreType::kS128Store:
847 Str(src.fp().Q(), dst_op);
848 break;
849 }
850}
851
852namespace liftoff {
853#define __ lasm->
854
857 Register addr_reg, Register offset_reg,
858 uintptr_t offset_imm) {
859 DCHECK_NE(addr_reg, no_reg);
860 if (offset_reg == no_reg && offset_imm == 0) return addr_reg;
861 Register result = temps.AcquireX();
862 if (offset_reg == no_reg) {
863 __ Add(result, addr_reg, Operand(offset_imm));
864 } else {
865 __ Add(result, addr_reg, Operand(offset_reg));
866 if (offset_imm != 0) __ Add(result, result, Operand(offset_imm));
867 }
868 return result;
869}
870
871enum class Binop { kAdd, kSub, kAnd, kOr, kXor, kExchange };
872
873inline void AtomicBinop(LiftoffAssembler* lasm, Register dst_addr,
874 Register offset_reg, uintptr_t offset_imm,
876 StoreType type, Binop op) {
877 LiftoffRegList pinned{dst_addr, value, result};
878 if (offset_reg != no_reg) pinned.set(offset_reg);
879 Register store_result = pinned.set(__ GetUnusedRegister(kGpReg, pinned)).gp();
880
881 // {LiftoffCompiler::AtomicBinop} ensures that {result} is unique.
882 DCHECK(result.gp() != value.gp() && result.gp() != dst_addr &&
883 result.gp() != offset_reg);
884
885 UseScratchRegisterScope temps(lasm);
887 lasm, temps, dst_addr, offset_reg, offset_imm);
888
889 if (CpuFeatures::IsSupported(LSE)) {
890 CpuFeatureScope scope(lasm, LSE);
891 switch (op) {
892 case Binop::kAnd:
893 switch (type.value()) {
894 case StoreType::kI64Store8:
895 case StoreType::kI32Store8: {
896 UseScratchRegisterScope temps(lasm);
897 Register temp = temps.AcquireW();
898 __ mvn(temp, value.gp().W());
899 __ ldclralb(temp, result.gp().W(), MemOperand(actual_addr));
900 break;
901 }
902 case StoreType::kI64Store16:
903 case StoreType::kI32Store16: {
904 UseScratchRegisterScope temps(lasm);
905 Register temp = temps.AcquireW();
906 __ mvn(temp, value.gp().W());
907 __ ldclralh(temp, result.gp().W(), MemOperand(actual_addr));
908 break;
909 }
910 case StoreType::kI64Store32:
911 case StoreType::kI32Store: {
912 UseScratchRegisterScope temps(lasm);
913 Register temp = temps.AcquireW();
914 __ mvn(temp, value.gp().W());
915 __ ldclral(temp, result.gp().W(), MemOperand(actual_addr));
916 break;
917 }
918 case StoreType::kI64Store: {
919 UseScratchRegisterScope temps(lasm);
920 Register temp = temps.AcquireX();
921 __ mvn(temp, value.gp());
922 __ ldclral(temp, result.gp(), MemOperand(actual_addr));
923 break;
924 }
925 default:
926 UNREACHABLE();
927 }
928 break;
929 case Binop::kSub:
930 switch (type.value()) {
931 case StoreType::kI64Store8:
932 case StoreType::kI32Store8: {
933 UseScratchRegisterScope temps(lasm);
934 Register temp = temps.AcquireW();
935 __ neg(temp, value.gp().W());
936 __ ldaddalb(temp, result.gp().W(), MemOperand(actual_addr));
937 break;
938 }
939 case StoreType::kI64Store16:
940 case StoreType::kI32Store16: {
941 UseScratchRegisterScope temps(lasm);
942 Register temp = temps.AcquireW();
943 __ neg(temp, value.gp().W());
944 __ ldaddalh(temp, result.gp().W(), MemOperand(actual_addr));
945 break;
946 }
947 case StoreType::kI64Store32:
948 case StoreType::kI32Store: {
949 UseScratchRegisterScope temps(lasm);
950 Register temp = temps.AcquireW();
951 __ neg(temp, value.gp().W());
952 __ ldaddal(temp, result.gp().W(), MemOperand(actual_addr));
953 break;
954 }
955 case StoreType::kI64Store: {
956 UseScratchRegisterScope temps(lasm);
957 Register temp = temps.AcquireX();
958 __ neg(temp, value.gp());
959 __ ldaddal(temp, result.gp(), MemOperand(actual_addr));
960 break;
961 }
962 default:
963 UNREACHABLE();
964 }
965 break;
966#define ATOMIC_BINOP_CASE(op, instr) \
967 case Binop::op: \
968 switch (type.value()) { \
969 case StoreType::kI64Store8: \
970 case StoreType::kI32Store8: \
971 __ instr##b(value.gp().W(), result.gp().W(), MemOperand(actual_addr)); \
972 break; \
973 case StoreType::kI64Store16: \
974 case StoreType::kI32Store16: \
975 __ instr##h(value.gp().W(), result.gp().W(), MemOperand(actual_addr)); \
976 break; \
977 case StoreType::kI64Store32: \
978 case StoreType::kI32Store: \
979 __ instr(value.gp().W(), result.gp().W(), MemOperand(actual_addr)); \
980 break; \
981 case StoreType::kI64Store: \
982 __ instr(value.gp(), result.gp(), MemOperand(actual_addr)); \
983 break; \
984 default: \
985 UNREACHABLE(); \
986 } \
987 break;
988 ATOMIC_BINOP_CASE(kAdd, ldaddal)
989 ATOMIC_BINOP_CASE(kOr, ldsetal)
990 ATOMIC_BINOP_CASE(kXor, ldeoral)
992#undef ATOMIC_BINOP_CASE
993 }
994 } else {
995 // Allocate an additional {temp} register to hold the result that should be
996 // stored to memory. Note that {temp} and {store_result} are not allowed to
997 // be the same register.
998 Register temp = temps.AcquireX();
999
1000 Label retry;
1001 __ Bind(&retry);
1002 switch (type.value()) {
1003 case StoreType::kI64Store8:
1004 case StoreType::kI32Store8:
1005 __ ldaxrb(result.gp().W(), actual_addr);
1006 break;
1007 case StoreType::kI64Store16:
1008 case StoreType::kI32Store16:
1009 __ ldaxrh(result.gp().W(), actual_addr);
1010 break;
1011 case StoreType::kI64Store32:
1012 case StoreType::kI32Store:
1013 __ ldaxr(result.gp().W(), actual_addr);
1014 break;
1015 case StoreType::kI64Store:
1016 __ ldaxr(result.gp().X(), actual_addr);
1017 break;
1018 default:
1019 UNREACHABLE();
1020 }
1021
1022 switch (op) {
1023 case Binop::kAdd:
1024 __ add(temp, result.gp(), value.gp());
1025 break;
1026 case Binop::kSub:
1027 __ sub(temp, result.gp(), value.gp());
1028 break;
1029 case Binop::kAnd:
1030 __ and_(temp, result.gp(), value.gp());
1031 break;
1032 case Binop::kOr:
1033 __ orr(temp, result.gp(), value.gp());
1034 break;
1035 case Binop::kXor:
1036 __ eor(temp, result.gp(), value.gp());
1037 break;
1038 case Binop::kExchange:
1039 __ mov(temp, value.gp());
1040 break;
1041 }
1042
1043 switch (type.value()) {
1044 case StoreType::kI64Store8:
1045 case StoreType::kI32Store8:
1046 __ stlxrb(store_result.W(), temp.W(), actual_addr);
1047 break;
1048 case StoreType::kI64Store16:
1049 case StoreType::kI32Store16:
1050 __ stlxrh(store_result.W(), temp.W(), actual_addr);
1051 break;
1052 case StoreType::kI64Store32:
1053 case StoreType::kI32Store:
1054 __ stlxr(store_result.W(), temp.W(), actual_addr);
1055 break;
1056 case StoreType::kI64Store:
1057 __ stlxr(store_result.W(), temp.X(), actual_addr);
1058 break;
1059 default:
1060 UNREACHABLE();
1061 }
1062
1063 __ Cbnz(store_result.W(), &retry);
1064 }
1065}
1066
1067#undef __
1068} // namespace liftoff
1069
1070void LiftoffAssembler::AtomicLoad(LiftoffRegister dst, Register src_addr,
1071 Register offset_reg, uintptr_t offset_imm,
1072 LoadType type, LiftoffRegList /* pinned */,
1073 bool /* i64_offset */) {
1074 UseScratchRegisterScope temps(this);
1075 Register src_reg = liftoff::CalculateActualAddress(this, temps, src_addr,
1076 offset_reg, offset_imm);
1077 switch (type.value()) {
1078 case LoadType::kI32Load8U:
1079 case LoadType::kI64Load8U:
1080 Ldarb(dst.gp().W(), src_reg);
1081 return;
1082 case LoadType::kI32Load16U:
1083 case LoadType::kI64Load16U:
1084 Ldarh(dst.gp().W(), src_reg);
1085 return;
1086 case LoadType::kI32Load:
1087 case LoadType::kI64Load32U:
1088 Ldar(dst.gp().W(), src_reg);
1089 return;
1090 case LoadType::kI64Load:
1091 Ldar(dst.gp().X(), src_reg);
1092 return;
1093 default:
1094 UNREACHABLE();
1095 }
1096}
1097
1098void LiftoffAssembler::AtomicStore(Register dst_addr, Register offset_reg,
1099 uintptr_t offset_imm, LiftoffRegister src,
1100 StoreType type, LiftoffRegList /* pinned */,
1101 bool /* i64_offset */) {
1102 UseScratchRegisterScope temps(this);
1103 Register dst_reg = liftoff::CalculateActualAddress(this, temps, dst_addr,
1104 offset_reg, offset_imm);
1105 switch (type.value()) {
1106 case StoreType::kI64Store8:
1107 case StoreType::kI32Store8:
1108 Stlrb(src.gp().W(), dst_reg);
1109 return;
1110 case StoreType::kI64Store16:
1111 case StoreType::kI32Store16:
1112 Stlrh(src.gp().W(), dst_reg);
1113 return;
1114 case StoreType::kI64Store32:
1115 case StoreType::kI32Store:
1116 Stlr(src.gp().W(), dst_reg);
1117 return;
1118 case StoreType::kI64Store:
1119 Stlr(src.gp().X(), dst_reg);
1120 return;
1121 default:
1122 UNREACHABLE();
1123 }
1124}
1125
1126void LiftoffAssembler::AtomicAdd(Register dst_addr, Register offset_reg,
1127 uintptr_t offset_imm, LiftoffRegister value,
1128 LiftoffRegister result, StoreType type,
1129 bool /* i64_offset */) {
1130 liftoff::AtomicBinop(this, dst_addr, offset_reg, offset_imm, value, result,
1131 type, liftoff::Binop::kAdd);
1132}
1133
1134void LiftoffAssembler::AtomicSub(Register dst_addr, Register offset_reg,
1135 uintptr_t offset_imm, LiftoffRegister value,
1136 LiftoffRegister result, StoreType type,
1137 bool /* i64_offset */) {
1138 liftoff::AtomicBinop(this, dst_addr, offset_reg, offset_imm, value, result,
1139 type, liftoff::Binop::kSub);
1140}
1141
1142void LiftoffAssembler::AtomicAnd(Register dst_addr, Register offset_reg,
1143 uintptr_t offset_imm, LiftoffRegister value,
1144 LiftoffRegister result, StoreType type,
1145 bool /* i64_offset */) {
1146 liftoff::AtomicBinop(this, dst_addr, offset_reg, offset_imm, value, result,
1147 type, liftoff::Binop::kAnd);
1148}
1149
1150void LiftoffAssembler::AtomicOr(Register dst_addr, Register offset_reg,
1151 uintptr_t offset_imm, LiftoffRegister value,
1152 LiftoffRegister result, StoreType type,
1153 bool /* i64_offset */) {
1154 liftoff::AtomicBinop(this, dst_addr, offset_reg, offset_imm, value, result,
1155 type, liftoff::Binop::kOr);
1156}
1157
1158void LiftoffAssembler::AtomicXor(Register dst_addr, Register offset_reg,
1159 uintptr_t offset_imm, LiftoffRegister value,
1160 LiftoffRegister result, StoreType type,
1161 bool /* i64_offset */) {
1162 liftoff::AtomicBinop(this, dst_addr, offset_reg, offset_imm, value, result,
1163 type, liftoff::Binop::kXor);
1164}
1165
1166void LiftoffAssembler::AtomicExchange(Register dst_addr, Register offset_reg,
1167 uintptr_t offset_imm,
1168 LiftoffRegister value,
1169 LiftoffRegister result, StoreType type,
1170 bool /* i64_offset */) {
1171 liftoff::AtomicBinop(this, dst_addr, offset_reg, offset_imm, value, result,
1173}
1174
1176 Register dst_addr, Register offset_reg, uintptr_t offset_imm,
1177 LiftoffRegister expected, LiftoffRegister new_value, LiftoffRegister result,
1178 StoreType type, bool /* i64_offset */) {
1179 LiftoffRegList pinned{dst_addr, expected, new_value};
1180 if (offset_reg != no_reg) pinned.set(offset_reg);
1181
1182 Register result_reg = result.gp();
1183 if (pinned.has(result)) {
1184 result_reg = GetUnusedRegister(kGpReg, pinned).gp();
1185 }
1186
1187 UseScratchRegisterScope temps(this);
1188
1190 this, temps, dst_addr, offset_reg, offset_imm);
1191
1192 if (CpuFeatures::IsSupported(LSE)) {
1193 CpuFeatureScope scope(this, LSE);
1194 switch (type.value()) {
1195 case StoreType::kI64Store8:
1196 case StoreType::kI32Store8:
1197 if (result.gp() != expected.gp()) {
1198 mov(result.gp().W(), expected.gp().W());
1199 }
1200 casalb(result.gp().W(), new_value.gp().W(), MemOperand(actual_addr));
1201 break;
1202 case StoreType::kI64Store16:
1203 case StoreType::kI32Store16:
1204 if (result.gp() != expected.gp()) {
1205 mov(result.gp().W(), expected.gp().W());
1206 }
1207 casalh(result.gp().W(), new_value.gp().W(), MemOperand(actual_addr));
1208 break;
1209 case StoreType::kI64Store32:
1210 case StoreType::kI32Store:
1211 if (result.gp() != expected.gp()) {
1212 mov(result.gp().W(), expected.gp().W());
1213 }
1214 casal(result.gp().W(), new_value.gp().W(), MemOperand(actual_addr));
1215 break;
1216 case StoreType::kI64Store:
1217 if (result.gp() != expected.gp()) {
1218 mov(result.gp().X(), expected.gp().X());
1219 }
1220 casal(result.gp().X(), new_value.gp().X(), MemOperand(actual_addr));
1221 break;
1222 default:
1223 UNREACHABLE();
1224 }
1225 } else {
1226 Register store_result = temps.AcquireW();
1227
1228 Label retry;
1229 Label done;
1230 Bind(&retry);
1231 switch (type.value()) {
1232 case StoreType::kI64Store8:
1233 case StoreType::kI32Store8:
1234 ldaxrb(result_reg.W(), actual_addr);
1235 Cmp(result.gp().W(), Operand(expected.gp().W(), UXTB));
1236 B(ne, &done);
1237 stlxrb(store_result.W(), new_value.gp().W(), actual_addr);
1238 break;
1239 case StoreType::kI64Store16:
1240 case StoreType::kI32Store16:
1241 ldaxrh(result_reg.W(), actual_addr);
1242 Cmp(result.gp().W(), Operand(expected.gp().W(), UXTH));
1243 B(ne, &done);
1244 stlxrh(store_result.W(), new_value.gp().W(), actual_addr);
1245 break;
1246 case StoreType::kI64Store32:
1247 case StoreType::kI32Store:
1248 ldaxr(result_reg.W(), actual_addr);
1249 Cmp(result.gp().W(), Operand(expected.gp().W(), UXTW));
1250 B(ne, &done);
1251 stlxr(store_result.W(), new_value.gp().W(), actual_addr);
1252 break;
1253 case StoreType::kI64Store:
1254 ldaxr(result_reg.X(), actual_addr);
1255 Cmp(result.gp().X(), Operand(expected.gp().X(), UXTX));
1256 B(ne, &done);
1257 stlxr(store_result.W(), new_value.gp().X(), actual_addr);
1258 break;
1259 default:
1260 UNREACHABLE();
1261 }
1262
1263 Cbnz(store_result.W(), &retry);
1264 Bind(&done);
1265 }
1266
1267 if (result_reg != result.gp()) {
1268 mov(result.gp(), result_reg);
1269 }
1270}
1271
1273
1274void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
1275 uint32_t caller_slot_idx,
1276 ValueKind kind) {
1277 int32_t offset = (caller_slot_idx + 1) * LiftoffAssembler::kStackSlotSize;
1279}
1280
1281void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src,
1282 uint32_t caller_slot_idx,
1284 Register frame_pointer) {
1285 int32_t offset = (caller_slot_idx + 1) * LiftoffAssembler::kStackSlotSize;
1286 Str(liftoff::GetRegFromType(src, kind), MemOperand(frame_pointer, offset));
1287}
1288
1289void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset,
1290 ValueKind kind) {
1292}
1293
1294void LiftoffAssembler::MoveStackValue(uint32_t dst_offset, uint32_t src_offset,
1295 ValueKind kind) {
1296 UseScratchRegisterScope temps(this);
1297 CPURegister scratch = liftoff::AcquireByType(&temps, kind);
1298 Ldr(scratch, liftoff::GetStackSlot(src_offset));
1299 Str(scratch, liftoff::GetStackSlot(dst_offset));
1300}
1301
1302void LiftoffAssembler::Move(Register dst, Register src, ValueKind kind) {
1303 if (kind == kI32) {
1304 Mov(dst.W(), src.W());
1305 } else {
1307 Mov(dst.X(), src.X());
1308 }
1309}
1310
1312 ValueKind kind) {
1313 if (kind == kF32) {
1314 Fmov(dst.S(), src.S());
1315 } else if (kind == kF64) {
1316 Fmov(dst.D(), src.D());
1317 } else {
1319 Mov(dst.Q(), src.Q());
1320 }
1321}
1322
1323void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueKind kind) {
1326 Str(liftoff::GetRegFromType(reg, kind), dst);
1327}
1328
1329void LiftoffAssembler::Spill(int offset, WasmValue value) {
1332 UseScratchRegisterScope temps(this);
1333 CPURegister src = CPURegister::no_reg();
1334 switch (value.type().kind()) {
1335 case kI32:
1336 if (value.to_i32() == 0) {
1337 src = wzr;
1338 } else {
1339 src = temps.AcquireW();
1340 Mov(src.W(), value.to_i32());
1341 }
1342 break;
1343 case kI64:
1344 if (value.to_i64() == 0) {
1345 src = xzr;
1346 } else {
1347 src = temps.AcquireX();
1348 Mov(src.X(), value.to_i64());
1349 }
1350 break;
1351 default:
1352 // We do not track f32 and f64 constants, hence they are unreachable.
1353 UNREACHABLE();
1354 }
1355 Str(src, dst);
1356}
1357
1358void LiftoffAssembler::Fill(LiftoffRegister reg, int offset, ValueKind kind) {
1361}
1362
1364 UNREACHABLE();
1365}
1366
1368 // Zero 'size' bytes *below* start, byte at offset 'start' is untouched.
1369 DCHECK_LE(0, start);
1370 DCHECK_LT(0, size);
1371 DCHECK_EQ(0, size % 4);
1373
1374 int max_stp_offset = -start - size;
1375 // We check IsImmLSUnscaled(-start-12) because str only allows for unscaled
1376 // 9-bit immediate offset [-256,256]. If start is large enough, which can
1377 // happen when a function has many params (>=32 i64), str cannot be encoded
1378 // properly. We can use Str, which will generate more instructions, so
1379 // fallback to the general case below.
1380 if (size <= 12 * kStackSlotSize &&
1381 IsImmLSPair(max_stp_offset, kXRegSizeLog2) &&
1382 IsImmLSUnscaled(-start - 12)) {
1383 // Special straight-line code for up to 12 slots. Generates one
1384 // instruction per two slots (<= 7 instructions total).
1385 static_assert(kStackSlotSize == kSystemPointerSize);
1386 uint32_t remainder = size;
1387 for (; remainder >= 2 * kStackSlotSize; remainder -= 2 * kStackSlotSize) {
1389 }
1390
1391 DCHECK_GE(12, remainder);
1392 switch (remainder) {
1393 case 12:
1396 break;
1397 case 8:
1399 break;
1400 case 4:
1402 break;
1403 case 0:
1404 break;
1405 default:
1406 UNREACHABLE();
1407 }
1408 } else {
1409 // General case for bigger counts (5-8 instructions).
1410 UseScratchRegisterScope temps(this);
1411 Register address_reg = temps.AcquireX();
1412 // This {Sub} might use another temp register if the offset is too large.
1413 Sub(address_reg, fp, start + size);
1414 Register count_reg = temps.AcquireX();
1415 Mov(count_reg, size / 4);
1416
1417 Label loop;
1418 bind(&loop);
1419 sub(count_reg, count_reg, 1);
1420 str(wzr, MemOperand(address_reg, kSystemPointerSize / 2, PostIndex));
1421 cbnz(count_reg, &loop);
1422 }
1423}
1424
1425void LiftoffAssembler::LoadSpillAddress(Register dst, int offset,
1426 ValueKind /* kind */) {
1427 Sub(dst, fp, offset);
1428}
1429
1430void LiftoffAssembler::emit_i32_add(Register dst, Register lhs, Register rhs) {
1431 Add(dst.W(), lhs.W(), rhs.W());
1432}
1433void LiftoffAssembler::emit_i32_addi(Register dst, Register lhs, int32_t imm) {
1434 Add(dst.W(), lhs.W(), Immediate(imm));
1435}
1436
1437void LiftoffAssembler::emit_i32_sub(Register dst, Register lhs, Register rhs) {
1438 Sub(dst.W(), lhs.W(), rhs.W());
1439}
1440void LiftoffAssembler::emit_i32_subi(Register dst, Register lhs, int32_t imm) {
1441 Sub(dst.W(), lhs.W(), Immediate(imm));
1442}
1443
1444void LiftoffAssembler::emit_i32_mul(Register dst, Register lhs, Register rhs) {
1445 Mul(dst.W(), lhs.W(), rhs.W());
1446}
1447
1448void LiftoffAssembler::emit_i32_and(Register dst, Register lhs, Register rhs) {
1449 And(dst.W(), lhs.W(), rhs.W());
1450}
1451void LiftoffAssembler::emit_i32_andi(Register dst, Register lhs, int32_t imm) {
1452 And(dst.W(), lhs.W(), Immediate(imm));
1453}
1454
1455void LiftoffAssembler::emit_i32_or(Register dst, Register lhs, Register rhs) {
1456 Orr(dst.W(), lhs.W(), rhs.W());
1457}
1458void LiftoffAssembler::emit_i32_ori(Register dst, Register lhs, int32_t imm) {
1459 Orr(dst.W(), lhs.W(), Immediate(imm));
1460}
1461
1462void LiftoffAssembler::emit_i32_xor(Register dst, Register lhs, Register rhs) {
1463 Eor(dst.W(), lhs.W(), rhs.W());
1464}
1465void LiftoffAssembler::emit_i32_xori(Register dst, Register lhs, int32_t imm) {
1466 Eor(dst.W(), lhs.W(), Immediate(imm));
1467}
1468
1469void LiftoffAssembler::emit_i32_shl(Register dst, Register src,
1470 Register amount) {
1471 Lsl(dst.W(), src.W(), amount.W());
1472}
1473void LiftoffAssembler::emit_i32_shli(Register dst, Register src,
1474 int32_t amount) {
1475 Lsl(dst.W(), src.W(), amount & 31);
1476}
1477
1478void LiftoffAssembler::emit_i32_sar(Register dst, Register src,
1479 Register amount) {
1480 Asr(dst.W(), src.W(), amount.W());
1481}
1482void LiftoffAssembler::emit_i32_sari(Register dst, Register src,
1483 int32_t amount) {
1484 Asr(dst.W(), src.W(), amount & 31);
1485}
1486
1487void LiftoffAssembler::emit_i32_shr(Register dst, Register src,
1488 Register amount) {
1489 Lsr(dst.W(), src.W(), amount.W());
1490}
1491void LiftoffAssembler::emit_i32_shri(Register dst, Register src,
1492 int32_t amount) {
1493 Lsr(dst.W(), src.W(), amount & 31);
1494}
1495
1496void LiftoffAssembler::emit_i64_add(LiftoffRegister dst, LiftoffRegister lhs,
1497 LiftoffRegister rhs) {
1498 Add(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1499}
1500
1501void LiftoffAssembler::emit_i64_sub(LiftoffRegister dst, LiftoffRegister lhs,
1502 LiftoffRegister rhs) {
1503 Sub(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1504}
1505
1506void LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs,
1507 LiftoffRegister rhs) {
1508 Mul(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1509}
1511 int32_t imm) {
1512 if (base::bits::IsPowerOfTwo(imm)) {
1514 return;
1515 }
1516 UseScratchRegisterScope temps(this);
1517 Register scratch = temps.AcquireX();
1518 Mov(scratch, imm);
1519 Mul(dst.gp().X(), lhs.gp().X(), scratch);
1520}
1521
1523 LiftoffRegister rhs) {
1524 And(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1525}
1527 int32_t imm) {
1528 And(dst.gp().X(), lhs.gp().X(), imm);
1529}
1530
1532 LiftoffRegister rhs) {
1533 Orr(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1534}
1536 int32_t imm) {
1537 Orr(dst.gp().X(), lhs.gp().X(), imm);
1538}
1539
1541 LiftoffRegister rhs) {
1542 Eor(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1543}
1545 int32_t imm) {
1546 Eor(dst.gp().X(), lhs.gp().X(), imm);
1547}
1548
1550 Register amount) {
1551 Lsl(dst.gp().X(), src.gp().X(), amount.X());
1552}
1553void LiftoffAssembler::emit_i64_shli(LiftoffRegister dst, LiftoffRegister src,
1554 int32_t amount) {
1555 Lsl(dst.gp().X(), src.gp().X(), amount & 63);
1556}
1557
1558void LiftoffAssembler::emit_i64_sar(LiftoffRegister dst, LiftoffRegister src,
1559 Register amount) {
1560 Asr(dst.gp().X(), src.gp().X(), amount.X());
1561}
1562void LiftoffAssembler::emit_i64_sari(LiftoffRegister dst, LiftoffRegister src,
1563 int32_t amount) {
1564 Asr(dst.gp().X(), src.gp().X(), amount & 63);
1565}
1566
1567void LiftoffAssembler::emit_i64_shr(LiftoffRegister dst, LiftoffRegister src,
1568 Register amount) {
1569 Lsr(dst.gp().X(), src.gp().X(), amount.X());
1570}
1571void LiftoffAssembler::emit_i64_shri(LiftoffRegister dst, LiftoffRegister src,
1572 int32_t amount) {
1573 Lsr(dst.gp().X(), src.gp().X(), amount & 63);
1574}
1575
1577 DoubleRegister rhs) {
1578 Fadd(dst.S(), lhs.S(), rhs.S());
1579}
1580
1582 DoubleRegister rhs) {
1583 Fsub(dst.S(), lhs.S(), rhs.S());
1584}
1585
1587 DoubleRegister rhs) {
1588 Fmul(dst.S(), lhs.S(), rhs.S());
1589}
1590
1592 DoubleRegister rhs) {
1593 Fdiv(dst.S(), lhs.S(), rhs.S());
1594}
1595
1597 DoubleRegister rhs) {
1598 Fmin(dst.S(), lhs.S(), rhs.S());
1599}
1600
1602 DoubleRegister rhs) {
1603 Fmax(dst.S(), lhs.S(), rhs.S());
1604}
1605
1607 Fabs(dst.S(), src.S());
1608}
1609
1611 Fneg(dst.S(), src.S());
1612}
1613
1615 Frintp(dst.S(), src.S());
1616 return true;
1617}
1618
1620 Frintm(dst.S(), src.S());
1621 return true;
1622}
1623
1625 Frintz(dst.S(), src.S());
1626 return true;
1627}
1628
1630 DoubleRegister src) {
1631 Frintn(dst.S(), src.S());
1632 return true;
1633}
1634
1636 Fsqrt(dst.S(), src.S());
1637}
1638
1640 DoubleRegister rhs) {
1641 Fadd(dst.D(), lhs.D(), rhs.D());
1642}
1643
1645 DoubleRegister rhs) {
1646 Fsub(dst.D(), lhs.D(), rhs.D());
1647}
1648
1650 DoubleRegister rhs) {
1651 Fmul(dst.D(), lhs.D(), rhs.D());
1652}
1653
1655 DoubleRegister rhs) {
1656 Fdiv(dst.D(), lhs.D(), rhs.D());
1657}
1658
1660 DoubleRegister rhs) {
1661 Fmin(dst.D(), lhs.D(), rhs.D());
1662}
1663
1665 DoubleRegister rhs) {
1666 Fmax(dst.D(), lhs.D(), rhs.D());
1667}
1668
1670 Fabs(dst.D(), src.D());
1671}
1672
1674 Fneg(dst.D(), src.D());
1675}
1676
1678 Frintp(dst.D(), src.D());
1679 return true;
1680}
1681
1683 Frintm(dst.D(), src.D());
1684 return true;
1685}
1686
1688 Frintz(dst.D(), src.D());
1689 return true;
1690}
1691
1693 DoubleRegister src) {
1694 Frintn(dst.D(), src.D());
1695 return true;
1696}
1697
1699 Fsqrt(dst.D(), src.D());
1700}
1701
1702void LiftoffAssembler::emit_i64_addi(LiftoffRegister dst, LiftoffRegister lhs,
1703 int64_t imm) {
1704 Add(dst.gp().X(), lhs.gp().X(), imm);
1705}
1706
1707void LiftoffAssembler::emit_i32_clz(Register dst, Register src) {
1708 Clz(dst.W(), src.W());
1709}
1710
1711void LiftoffAssembler::emit_i32_ctz(Register dst, Register src) {
1712 Rbit(dst.W(), src.W());
1713 Clz(dst.W(), dst.W());
1714}
1715
1716bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
1717 PopcntHelper(dst.W(), src.W());
1718 return true;
1719}
1720
1721void LiftoffAssembler::emit_i64_clz(LiftoffRegister dst, LiftoffRegister src) {
1722 Clz(dst.gp().X(), src.gp().X());
1723}
1724
1725void LiftoffAssembler::emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src) {
1726 Rbit(dst.gp().X(), src.gp().X());
1727 Clz(dst.gp().X(), dst.gp().X());
1728}
1729
1730bool LiftoffAssembler::emit_i64_popcnt(LiftoffRegister dst,
1731 LiftoffRegister src) {
1732 PopcntHelper(dst.gp().X(), src.gp().X());
1733 return true;
1734}
1735
1736void LiftoffAssembler::IncrementSmi(LiftoffRegister dst, int offset) {
1737 UseScratchRegisterScope temps(this);
1740 Register scratch = temps.AcquireW();
1741 Ldr(scratch, MemOperand(dst.gp(), offset));
1742 Add(scratch, scratch, Operand(Smi::FromInt(1)));
1743 Str(scratch, MemOperand(dst.gp(), offset));
1744 } else {
1745 Register scratch = temps.AcquireX();
1746 SmiUntag(scratch, MemOperand(dst.gp(), offset));
1747 Add(scratch, scratch, Operand(1));
1748 SmiTag(scratch);
1749 Str(scratch, MemOperand(dst.gp(), offset));
1750 }
1751}
1752
1753void LiftoffAssembler::emit_i32_divs(Register dst, Register lhs, Register rhs,
1754 Label* trap_div_by_zero,
1755 Label* trap_div_unrepresentable) {
1756 Register dst_w = dst.W();
1757 Register lhs_w = lhs.W();
1758 Register rhs_w = rhs.W();
1759 bool can_use_dst = !dst_w.Aliases(lhs_w) && !dst_w.Aliases(rhs_w);
1760 if (can_use_dst) {
1761 // Do div early.
1762 Sdiv(dst_w, lhs_w, rhs_w);
1763 }
1764 // Check for division by zero.
1765 Cbz(rhs_w, trap_div_by_zero);
1766 // Check for kMinInt / -1. This is unrepresentable.
1767 Cmp(rhs_w, -1);
1768 Ccmp(lhs_w, 1, NoFlag, eq);
1769 B(trap_div_unrepresentable, vs);
1770 if (!can_use_dst) {
1771 // Do div.
1772 Sdiv(dst_w, lhs_w, rhs_w);
1773 }
1774}
1775
1776void LiftoffAssembler::emit_i32_divu(Register dst, Register lhs, Register rhs,
1777 Label* trap_div_by_zero) {
1778 // Check for division by zero.
1779 Cbz(rhs.W(), trap_div_by_zero);
1780 // Do div.
1781 Udiv(dst.W(), lhs.W(), rhs.W());
1782}
1783
1784void LiftoffAssembler::emit_i32_rems(Register dst, Register lhs, Register rhs,
1785 Label* trap_div_by_zero) {
1786 Register dst_w = dst.W();
1787 Register lhs_w = lhs.W();
1788 Register rhs_w = rhs.W();
1789 // Do early div.
1790 // No need to check kMinInt / -1 because the result is kMinInt and then
1791 // kMinInt * -1 -> kMinInt. In this case, the Msub result is therefore 0.
1792 UseScratchRegisterScope temps(this);
1793 Register scratch = temps.AcquireW();
1794 Sdiv(scratch, lhs_w, rhs_w);
1795 // Check for division by zero.
1796 Cbz(rhs_w, trap_div_by_zero);
1797 // Compute remainder.
1798 Msub(dst_w, scratch, rhs_w, lhs_w);
1799}
1800
1801void LiftoffAssembler::emit_i32_remu(Register dst, Register lhs, Register rhs,
1802 Label* trap_div_by_zero) {
1803 Register dst_w = dst.W();
1804 Register lhs_w = lhs.W();
1805 Register rhs_w = rhs.W();
1806 // Do early div.
1807 UseScratchRegisterScope temps(this);
1808 Register scratch = temps.AcquireW();
1809 Udiv(scratch, lhs_w, rhs_w);
1810 // Check for division by zero.
1811 Cbz(rhs_w, trap_div_by_zero);
1812 // Compute remainder.
1813 Msub(dst_w, scratch, rhs_w, lhs_w);
1814}
1815
1816bool LiftoffAssembler::emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs,
1817 LiftoffRegister rhs,
1818 Label* trap_div_by_zero,
1819 Label* trap_div_unrepresentable) {
1820 Register dst_x = dst.gp().X();
1821 Register lhs_x = lhs.gp().X();
1822 Register rhs_x = rhs.gp().X();
1823 bool can_use_dst = !dst_x.Aliases(lhs_x) && !dst_x.Aliases(rhs_x);
1824 if (can_use_dst) {
1825 // Do div early.
1826 Sdiv(dst_x, lhs_x, rhs_x);
1827 }
1828 // Check for division by zero.
1829 Cbz(rhs_x, trap_div_by_zero);
1830 // Check for kMinInt / -1. This is unrepresentable.
1831 Cmp(rhs_x, -1);
1832 Ccmp(lhs_x, 1, NoFlag, eq);
1833 B(trap_div_unrepresentable, vs);
1834 if (!can_use_dst) {
1835 // Do div.
1836 Sdiv(dst_x, lhs_x, rhs_x);
1837 }
1838 return true;
1839}
1840
1841bool LiftoffAssembler::emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs,
1842 LiftoffRegister rhs,
1843 Label* trap_div_by_zero) {
1844 // Check for division by zero.
1845 Cbz(rhs.gp().X(), trap_div_by_zero);
1846 // Do div.
1847 Udiv(dst.gp().X(), lhs.gp().X(), rhs.gp().X());
1848 return true;
1849}
1850
1851bool LiftoffAssembler::emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs,
1852 LiftoffRegister rhs,
1853 Label* trap_div_by_zero) {
1854 Register dst_x = dst.gp().X();
1855 Register lhs_x = lhs.gp().X();
1856 Register rhs_x = rhs.gp().X();
1857 // Do early div.
1858 // No need to check kMinInt / -1 because the result is kMinInt and then
1859 // kMinInt * -1 -> kMinInt. In this case, the Msub result is therefore 0.
1860 UseScratchRegisterScope temps(this);
1861 Register scratch = temps.AcquireX();
1862 Sdiv(scratch, lhs_x, rhs_x);
1863 // Check for division by zero.
1864 Cbz(rhs_x, trap_div_by_zero);
1865 // Compute remainder.
1866 Msub(dst_x, scratch, rhs_x, lhs_x);
1867 return true;
1868}
1869
1870bool LiftoffAssembler::emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs,
1871 LiftoffRegister rhs,
1872 Label* trap_div_by_zero) {
1873 Register dst_x = dst.gp().X();
1874 Register lhs_x = lhs.gp().X();
1875 Register rhs_x = rhs.gp().X();
1876 // Do early div.
1877 UseScratchRegisterScope temps(this);
1878 Register scratch = temps.AcquireX();
1879 Udiv(scratch, lhs_x, rhs_x);
1880 // Check for division by zero.
1881 Cbz(rhs_x, trap_div_by_zero);
1882 // Compute remainder.
1883 Msub(dst_x, scratch, rhs_x, lhs_x);
1884 return true;
1885}
1886
1888 Uxtw(dst, src);
1889}
1890
1892
1894 DoubleRegister rhs) {
1895 UseScratchRegisterScope temps(this);
1896 DoubleRegister scratch = temps.AcquireD();
1897 Ushr(scratch.V2S(), rhs.V2S(), 31);
1898 if (dst != lhs) {
1899 Fmov(dst.S(), lhs.S());
1900 }
1901 Sli(dst.V2S(), scratch.V2S(), 31);
1902}
1903
1905 DoubleRegister rhs) {
1906 UseScratchRegisterScope temps(this);
1907 DoubleRegister scratch = temps.AcquireD();
1908 Ushr(scratch.V1D(), rhs.V1D(), 63);
1909 if (dst != lhs) {
1910 Fmov(dst.D(), lhs.D());
1911 }
1912 Sli(dst.V1D(), scratch.V1D(), 63);
1913}
1914
1916 LiftoffRegister dst,
1917 LiftoffRegister src, Label* trap) {
1918 switch (opcode) {
1919 case kExprI32ConvertI64:
1920 Mov(dst.gp().W(), src.gp().W());
1921 return true;
1922 case kExprI32SConvertF32:
1923 Fcvtzs(dst.gp().W(), src.fp().S()); // f32 -> i32 round to zero.
1924 // Check underflow and NaN.
1925 Fcmp(src.fp().S(), static_cast<float>(INT32_MIN));
1926 // Check overflow.
1927 Ccmp(dst.gp().W(), -1, VFlag, ge);
1928 B(trap, vs);
1929 return true;
1930 case kExprI32UConvertF32:
1931 Fcvtzu(dst.gp().W(), src.fp().S()); // f32 -> i32 round to zero.
1932 // Check underflow and NaN.
1933 Fcmp(src.fp().S(), -1.0);
1934 // Check overflow.
1935 Ccmp(dst.gp().W(), -1, ZFlag, gt);
1936 B(trap, eq);
1937 return true;
1938 case kExprI32SConvertF64: {
1939 // INT32_MIN and INT32_MAX are valid results, we cannot test the result
1940 // to detect the overflows. We could have done two immediate floating
1941 // point comparisons but it would have generated two conditional branches.
1942 UseScratchRegisterScope temps(this);
1943 VRegister fp_ref = temps.AcquireD();
1944 VRegister fp_cmp = temps.AcquireD();
1945 Fcvtzs(dst.gp().W(), src.fp().D()); // f64 -> i32 round to zero.
1946 Frintz(fp_ref, src.fp().D()); // f64 -> f64 round to zero.
1947 Scvtf(fp_cmp, dst.gp().W()); // i32 -> f64.
1948 // If comparison fails, we have an overflow or a NaN.
1949 Fcmp(fp_cmp, fp_ref);
1950 B(trap, ne);
1951 return true;
1952 }
1953 case kExprI32UConvertF64: {
1954 // INT32_MAX is a valid result, we cannot test the result to detect the
1955 // overflows. We could have done two immediate floating point comparisons
1956 // but it would have generated two conditional branches.
1957 UseScratchRegisterScope temps(this);
1958 VRegister fp_ref = temps.AcquireD();
1959 VRegister fp_cmp = temps.AcquireD();
1960 Fcvtzu(dst.gp().W(), src.fp().D()); // f64 -> i32 round to zero.
1961 Frintz(fp_ref, src.fp().D()); // f64 -> f64 round to zero.
1962 Ucvtf(fp_cmp, dst.gp().W()); // i32 -> f64.
1963 // If comparison fails, we have an overflow or a NaN.
1964 Fcmp(fp_cmp, fp_ref);
1965 B(trap, ne);
1966 return true;
1967 }
1968 case kExprI32SConvertSatF32:
1969 Fcvtzs(dst.gp().W(), src.fp().S());
1970 return true;
1971 case kExprI32UConvertSatF32:
1972 Fcvtzu(dst.gp().W(), src.fp().S());
1973 return true;
1974 case kExprI32SConvertSatF64:
1975 Fcvtzs(dst.gp().W(), src.fp().D());
1976 return true;
1977 case kExprI32UConvertSatF64:
1978 Fcvtzu(dst.gp().W(), src.fp().D());
1979 return true;
1980 case kExprI64SConvertSatF32:
1981 Fcvtzs(dst.gp().X(), src.fp().S());
1982 return true;
1983 case kExprI64UConvertSatF32:
1984 Fcvtzu(dst.gp().X(), src.fp().S());
1985 return true;
1986 case kExprI64SConvertSatF64:
1987 Fcvtzs(dst.gp().X(), src.fp().D());
1988 return true;
1989 case kExprI64UConvertSatF64:
1990 Fcvtzu(dst.gp().X(), src.fp().D());
1991 return true;
1992 case kExprI32ReinterpretF32:
1993 Fmov(dst.gp().W(), src.fp().S());
1994 return true;
1995 case kExprI64SConvertI32:
1996 Sxtw(dst.gp().X(), src.gp().W());
1997 return true;
1998 case kExprI64SConvertF32:
1999 Fcvtzs(dst.gp().X(), src.fp().S()); // f32 -> i64 round to zero.
2000 // Check underflow and NaN.
2001 Fcmp(src.fp().S(), static_cast<float>(INT64_MIN));
2002 // Check overflow.
2003 Ccmp(dst.gp().X(), -1, VFlag, ge);
2004 B(trap, vs);
2005 return true;
2006 case kExprI64UConvertF32:
2007 Fcvtzu(dst.gp().X(), src.fp().S()); // f32 -> i64 round to zero.
2008 // Check underflow and NaN.
2009 Fcmp(src.fp().S(), -1.0);
2010 // Check overflow.
2011 Ccmp(dst.gp().X(), -1, ZFlag, gt);
2012 B(trap, eq);
2013 return true;
2014 case kExprI64SConvertF64:
2015 Fcvtzs(dst.gp().X(), src.fp().D()); // f64 -> i64 round to zero.
2016 // Check underflow and NaN.
2017 Fcmp(src.fp().D(), static_cast<float>(INT64_MIN));
2018 // Check overflow.
2019 Ccmp(dst.gp().X(), -1, VFlag, ge);
2020 B(trap, vs);
2021 return true;
2022 case kExprI64UConvertF64:
2023 Fcvtzu(dst.gp().X(), src.fp().D()); // f64 -> i64 round to zero.
2024 // Check underflow and NaN.
2025 Fcmp(src.fp().D(), -1.0);
2026 // Check overflow.
2027 Ccmp(dst.gp().X(), -1, ZFlag, gt);
2028 B(trap, eq);
2029 return true;
2030 case kExprI64UConvertI32:
2031 Mov(dst.gp().W(), src.gp().W());
2032 return true;
2033 case kExprI64ReinterpretF64:
2034 Fmov(dst.gp().X(), src.fp().D());
2035 return true;
2036 case kExprF32SConvertI32:
2037 Scvtf(dst.fp().S(), src.gp().W());
2038 return true;
2039 case kExprF32UConvertI32:
2040 Ucvtf(dst.fp().S(), src.gp().W());
2041 return true;
2042 case kExprF32SConvertI64:
2043 Scvtf(dst.fp().S(), src.gp().X());
2044 return true;
2045 case kExprF32UConvertI64:
2046 Ucvtf(dst.fp().S(), src.gp().X());
2047 return true;
2048 case kExprF32ConvertF64:
2049 Fcvt(dst.fp().S(), src.fp().D());
2050 return true;
2051 case kExprF32ReinterpretI32:
2052 Fmov(dst.fp().S(), src.gp().W());
2053 return true;
2054 case kExprF64SConvertI32:
2055 Scvtf(dst.fp().D(), src.gp().W());
2056 return true;
2057 case kExprF64UConvertI32:
2058 Ucvtf(dst.fp().D(), src.gp().W());
2059 return true;
2060 case kExprF64SConvertI64:
2061 Scvtf(dst.fp().D(), src.gp().X());
2062 return true;
2063 case kExprF64UConvertI64:
2064 Ucvtf(dst.fp().D(), src.gp().X());
2065 return true;
2066 case kExprF64ConvertF32:
2067 Fcvt(dst.fp().D(), src.fp().S());
2068 return true;
2069 case kExprF64ReinterpretI64:
2070 Fmov(dst.fp().D(), src.gp().X());
2071 return true;
2072 default:
2073 UNREACHABLE();
2074 }
2075}
2076
2077void LiftoffAssembler::emit_i32_signextend_i8(Register dst, Register src) {
2078 sxtb(dst.W(), src.W());
2079}
2080
2081void LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) {
2082 sxth(dst.W(), src.W());
2083}
2084
2085void LiftoffAssembler::emit_i64_signextend_i8(LiftoffRegister dst,
2086 LiftoffRegister src) {
2087 sxtb(dst.gp(), src.gp());
2088}
2089
2090void LiftoffAssembler::emit_i64_signextend_i16(LiftoffRegister dst,
2091 LiftoffRegister src) {
2092 sxth(dst.gp(), src.gp());
2093}
2094
2095void LiftoffAssembler::emit_i64_signextend_i32(LiftoffRegister dst,
2096 LiftoffRegister src) {
2097 sxtw(dst.gp(), src.gp());
2098}
2099
2100void LiftoffAssembler::emit_jump(Label* label) { B(label); }
2101
2102void LiftoffAssembler::emit_jump(Register target) { Br(target); }
2103
2105 ValueKind kind, Register lhs,
2106 Register rhs,
2107 const FreezeCacheState& frozen) {
2108 switch (kind) {
2109 case kI32:
2110 if (rhs.is_valid()) {
2111 Cmp(lhs.W(), rhs.W());
2112 } else {
2113 Cmp(lhs.W(), wzr);
2114 }
2115 break;
2116 case kRef:
2117 case kRefNull:
2118 DCHECK(rhs.is_valid());
2119 DCHECK(cond == kEqual || cond == kNotEqual);
2120#if defined(V8_COMPRESS_POINTERS)
2121 Cmp(lhs.W(), rhs.W());
2122#else
2123 Cmp(lhs.X(), rhs.X());
2124#endif
2125 break;
2126 case kI64:
2127 if (rhs.is_valid()) {
2128 Cmp(lhs.X(), rhs.X());
2129 } else {
2130 Cmp(lhs.X(), xzr);
2131 }
2132 break;
2133 default:
2134 UNREACHABLE();
2135 }
2136 B(label, cond);
2137}
2138
2140 Register lhs, int32_t imm,
2141 const FreezeCacheState& frozen) {
2142 Cmp(lhs.W(), Operand(imm));
2143 B(label, cond);
2144}
2145
2147 Register lhs, int32_t imm,
2148 const FreezeCacheState& frozen) {
2149 Cmp(lhs.X(), Operand(imm));
2150 B(label, cond);
2151}
2152
2154 Cmp(src.W(), wzr);
2155 Cset(dst.W(), eq);
2156}
2157
2159 Register lhs, Register rhs) {
2160 Cmp(lhs.W(), rhs.W());
2161 Cset(dst.W(), cond);
2162}
2163
2164void LiftoffAssembler::emit_i64_eqz(Register dst, LiftoffRegister src) {
2165 Cmp(src.gp().X(), xzr);
2166 Cset(dst.W(), eq);
2167}
2168
2169void LiftoffAssembler::emit_i64_set_cond(Condition cond, Register dst,
2170 LiftoffRegister lhs,
2171 LiftoffRegister rhs) {
2172 Cmp(lhs.gp().X(), rhs.gp().X());
2173 Cset(dst.W(), cond);
2174}
2175
2176void LiftoffAssembler::emit_f32_set_cond(Condition cond, Register dst,
2177 DoubleRegister lhs,
2178 DoubleRegister rhs) {
2179 Fcmp(lhs.S(), rhs.S());
2180 Cset(dst.W(), cond);
2181 if (cond != ne) {
2182 // If V flag set, at least one of the arguments was a Nan -> false.
2183 Csel(dst.W(), wzr, dst.W(), vs);
2184 }
2185}
2186
2187void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
2188 DoubleRegister lhs,
2189 DoubleRegister rhs) {
2190 Fcmp(lhs.D(), rhs.D());
2191 Cset(dst.W(), cond);
2192 if (cond != ne) {
2193 // If V flag set, at least one of the arguments was a Nan -> false.
2194 Csel(dst.W(), wzr, dst.W(), vs);
2195 }
2196}
2197
2198bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
2199 LiftoffRegister true_value,
2200 LiftoffRegister false_value,
2201 ValueKind kind) {
2202 if (kind != kI32 && kind != kI64 && kind != kF32 && kind != kF64)
2203 return false;
2204
2205 Cmp(condition.W(), wzr);
2206 switch (kind) {
2207 default:
2208 UNREACHABLE();
2209 case kI32:
2210 Csel(dst.gp().W(), true_value.gp().W(), false_value.gp().W(), ne);
2211 break;
2212 case kI64:
2213 Csel(dst.gp().X(), true_value.gp().X(), false_value.gp().X(), ne);
2214 break;
2215 case kF32:
2216 Fcsel(dst.fp().S(), true_value.fp().S(), false_value.fp().S(), ne);
2217 break;
2218 case kF64:
2219 Fcsel(dst.fp().D(), true_value.fp().D(), false_value.fp().D(), ne);
2220 break;
2221 }
2222 return true;
2223}
2224
2225void LiftoffAssembler::emit_smi_check(Register obj, Label* target,
2226 SmiCheckMode mode,
2227 const FreezeCacheState& frozen) {
2228 Label* smi_label = mode == kJumpOnSmi ? target : nullptr;
2229 Label* not_smi_label = mode == kJumpOnNotSmi ? target : nullptr;
2230 JumpIfSmi(obj, smi_label, not_smi_label);
2231}
2232
2233void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
2234 Register offset_reg, uintptr_t offset_imm,
2235 LoadType type,
2236 LoadTransformationKind transform,
2237 uint32_t* protected_load_pc,
2238 bool i64_offset) {
2239 UseScratchRegisterScope temps(this);
2240 MemOperand src_op =
2242 ? MemOperand{liftoff::GetEffectiveAddress(this, &temps, src_addr,
2243 offset_reg, offset_imm)}
2244 : liftoff::GetMemOp(this, &temps, src_addr, offset_reg, offset_imm,
2245 i64_offset);
2246 *protected_load_pc = pc_offset();
2247 MachineType memtype = type.mem_type();
2248
2249 if (transform == LoadTransformationKind::kExtend) {
2250 if (memtype == MachineType::Int8()) {
2251 Ldr(dst.fp().D(), src_op);
2252 Sxtl(dst.fp().V8H(), dst.fp().V8B());
2253 } else if (memtype == MachineType::Uint8()) {
2254 Ldr(dst.fp().D(), src_op);
2255 Uxtl(dst.fp().V8H(), dst.fp().V8B());
2256 } else if (memtype == MachineType::Int16()) {
2257 Ldr(dst.fp().D(), src_op);
2258 Sxtl(dst.fp().V4S(), dst.fp().V4H());
2259 } else if (memtype == MachineType::Uint16()) {
2260 Ldr(dst.fp().D(), src_op);
2261 Uxtl(dst.fp().V4S(), dst.fp().V4H());
2262 } else if (memtype == MachineType::Int32()) {
2263 Ldr(dst.fp().D(), src_op);
2264 Sxtl(dst.fp().V2D(), dst.fp().V2S());
2265 } else if (memtype == MachineType::Uint32()) {
2266 Ldr(dst.fp().D(), src_op);
2267 Uxtl(dst.fp().V2D(), dst.fp().V2S());
2268 }
2269 } else if (transform == LoadTransformationKind::kZeroExtend) {
2270 if (memtype == MachineType::Int32()) {
2271 Ldr(dst.fp().S(), src_op);
2272 } else {
2273 DCHECK_EQ(MachineType::Int64(), memtype);
2274 Ldr(dst.fp().D(), src_op);
2275 }
2276 } else {
2278 if (memtype == MachineType::Int8()) {
2279 ld1r(dst.fp().V16B(), src_op);
2280 } else if (memtype == MachineType::Int16()) {
2281 ld1r(dst.fp().V8H(), src_op);
2282 } else if (memtype == MachineType::Int32()) {
2283 ld1r(dst.fp().V4S(), src_op);
2284 } else if (memtype == MachineType::Int64()) {
2285 ld1r(dst.fp().V2D(), src_op);
2286 }
2287 }
2288}
2289
2290void LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src,
2291 Register addr, Register offset_reg,
2292 uintptr_t offset_imm, LoadType type,
2293 uint8_t laneidx, uint32_t* protected_load_pc,
2294 bool i64_offset) {
2295 UseScratchRegisterScope temps(this);
2296 MemOperand src_op{liftoff::GetEffectiveAddress(this, &temps, addr, offset_reg,
2297 offset_imm, i64_offset)};
2298
2299 MachineType mem_type = type.mem_type();
2300 if (dst != src) {
2301 Mov(dst.fp().Q(), src.fp().Q());
2302 }
2303
2304 *protected_load_pc = pc_offset();
2305 if (mem_type == MachineType::Int8()) {
2306 ld1(dst.fp().B(), laneidx, src_op);
2307 } else if (mem_type == MachineType::Int16()) {
2308 ld1(dst.fp().H(), laneidx, src_op);
2309 } else if (mem_type == MachineType::Int32()) {
2310 ld1(dst.fp().S(), laneidx, src_op);
2311 } else if (mem_type == MachineType::Int64()) {
2312 ld1(dst.fp().D(), laneidx, src_op);
2313 } else {
2314 UNREACHABLE();
2315 }
2316}
2317
2318void LiftoffAssembler::StoreLane(Register dst, Register offset,
2319 uintptr_t offset_imm, LiftoffRegister src,
2320 StoreType type, uint8_t lane,
2321 uint32_t* protected_store_pc,
2322 bool i64_offset) {
2323 UseScratchRegisterScope temps(this);
2324 MemOperand dst_op{liftoff::GetEffectiveAddress(this, &temps, dst, offset,
2325 offset_imm, i64_offset)};
2326 if (protected_store_pc) *protected_store_pc = pc_offset();
2327
2328 MachineRepresentation rep = type.mem_rep();
2329 if (rep == MachineRepresentation::kWord8) {
2330 st1(src.fp().B(), lane, dst_op);
2331 } else if (rep == MachineRepresentation::kWord16) {
2332 st1(src.fp().H(), lane, dst_op);
2333 } else if (rep == MachineRepresentation::kWord32) {
2334 st1(src.fp().S(), lane, dst_op);
2335 } else {
2337 st1(src.fp().D(), lane, dst_op);
2338 }
2339}
2340
2341void LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst,
2342 LiftoffRegister lhs,
2343 LiftoffRegister rhs) {
2344 Tbl(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
2345}
2346
2347void LiftoffAssembler::emit_i8x16_relaxed_swizzle(LiftoffRegister dst,
2348 LiftoffRegister lhs,
2349 LiftoffRegister rhs) {
2350 Tbl(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
2351}
2352
2354 LiftoffRegister src) {
2355 Fcvtzs(dst.fp().V4S(), src.fp().V4S());
2356}
2357
2359 LiftoffRegister src) {
2360 Fcvtzu(dst.fp().V4S(), src.fp().V4S());
2361}
2362
2364 LiftoffRegister dst, LiftoffRegister src) {
2365 Fcvtzs(dst.fp().V2D(), src.fp().V2D());
2366 Sqxtn(dst.fp().V2S(), dst.fp().V2D());
2367}
2368
2370 LiftoffRegister dst, LiftoffRegister src) {
2371 Fcvtzu(dst.fp().V2D(), src.fp().V2D());
2372 Uqxtn(dst.fp().V2S(), dst.fp().V2D());
2373}
2374
2375void LiftoffAssembler::emit_s128_relaxed_laneselect(LiftoffRegister dst,
2376 LiftoffRegister src1,
2377 LiftoffRegister src2,
2378 LiftoffRegister mask,
2379 int lane_width) {
2380 // ARM64 uses bytewise selection for all lane widths.
2381 emit_s128_select(dst, src1, src2, mask);
2382}
2383
2384void LiftoffAssembler::emit_f64x2_splat(LiftoffRegister dst,
2385 LiftoffRegister src) {
2386 Dup(dst.fp().V2D(), src.fp().D(), 0);
2387}
2388
2389void LiftoffAssembler::emit_f64x2_extract_lane(LiftoffRegister dst,
2390 LiftoffRegister lhs,
2391 uint8_t imm_lane_idx) {
2392 Mov(dst.fp().D(), lhs.fp().V2D(), imm_lane_idx);
2393}
2394
2395void LiftoffAssembler::emit_f64x2_replace_lane(LiftoffRegister dst,
2396 LiftoffRegister src1,
2397 LiftoffRegister src2,
2398 uint8_t imm_lane_idx) {
2399 if (dst != src1) {
2400 Mov(dst.fp().V2D(), src1.fp().V2D());
2401 }
2402 Mov(dst.fp().V2D(), imm_lane_idx, src2.fp().V2D(), 0);
2403}
2404
2405void LiftoffAssembler::emit_f64x2_abs(LiftoffRegister dst,
2406 LiftoffRegister src) {
2407 Fabs(dst.fp().V2D(), src.fp().V2D());
2408}
2409
2410void LiftoffAssembler::emit_f64x2_neg(LiftoffRegister dst,
2411 LiftoffRegister src) {
2412 Fneg(dst.fp().V2D(), src.fp().V2D());
2413}
2414
2415void LiftoffAssembler::emit_f64x2_sqrt(LiftoffRegister dst,
2416 LiftoffRegister src) {
2417 Fsqrt(dst.fp().V2D(), src.fp().V2D());
2418}
2419
2420bool LiftoffAssembler::emit_f64x2_ceil(LiftoffRegister dst,
2421 LiftoffRegister src) {
2422 Frintp(dst.fp().V2D(), src.fp().V2D());
2423 return true;
2424}
2425
2426bool LiftoffAssembler::emit_f64x2_floor(LiftoffRegister dst,
2427 LiftoffRegister src) {
2428 Frintm(dst.fp().V2D(), src.fp().V2D());
2429 return true;
2430}
2431
2432bool LiftoffAssembler::emit_f64x2_trunc(LiftoffRegister dst,
2433 LiftoffRegister src) {
2434 Frintz(dst.fp().V2D(), src.fp().V2D());
2435 return true;
2436}
2437
2438bool LiftoffAssembler::emit_f64x2_nearest_int(LiftoffRegister dst,
2439 LiftoffRegister src) {
2440 Frintn(dst.fp().V2D(), src.fp().V2D());
2441 return true;
2442}
2443
2444void LiftoffAssembler::emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs,
2445 LiftoffRegister rhs) {
2446 Fadd(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2447}
2448
2449void LiftoffAssembler::emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs,
2450 LiftoffRegister rhs) {
2451 Fsub(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2452}
2453
2454void LiftoffAssembler::emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs,
2455 LiftoffRegister rhs) {
2456 Fmul(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2457}
2458
2459void LiftoffAssembler::emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs,
2460 LiftoffRegister rhs) {
2461 Fdiv(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2462}
2463
2464void LiftoffAssembler::emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs,
2465 LiftoffRegister rhs) {
2466 Fmin(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2467}
2468
2469void LiftoffAssembler::emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs,
2470 LiftoffRegister rhs) {
2471 Fmax(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2472}
2473
2474void LiftoffAssembler::emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs,
2475 LiftoffRegister rhs) {
2476 UseScratchRegisterScope temps(this);
2477
2478 VRegister tmp = dst.fp();
2479 if (dst == lhs || dst == rhs) {
2480 tmp = temps.AcquireV(kFormat2D);
2481 }
2482
2483 Fcmgt(tmp.V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2484 Bsl(tmp.V16B(), rhs.fp().V16B(), lhs.fp().V16B());
2485
2486 if (dst == lhs || dst == rhs) {
2487 Mov(dst.fp().V2D(), tmp);
2488 }
2489}
2490
2491void LiftoffAssembler::emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs,
2492 LiftoffRegister rhs) {
2493 UseScratchRegisterScope temps(this);
2494
2495 VRegister tmp = dst.fp();
2496 if (dst == lhs || dst == rhs) {
2497 tmp = temps.AcquireV(kFormat2D);
2498 }
2499
2500 Fcmgt(tmp.V2D(), rhs.fp().V2D(), lhs.fp().V2D());
2501 Bsl(tmp.V16B(), rhs.fp().V16B(), lhs.fp().V16B());
2502
2503 if (dst == lhs || dst == rhs) {
2504 Mov(dst.fp().V2D(), tmp);
2505 }
2506}
2507
2508void LiftoffAssembler::emit_f64x2_relaxed_min(LiftoffRegister dst,
2509 LiftoffRegister lhs,
2510 LiftoffRegister rhs) {
2511 Fmin(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2512}
2513
2514void LiftoffAssembler::emit_f64x2_relaxed_max(LiftoffRegister dst,
2515 LiftoffRegister lhs,
2516 LiftoffRegister rhs) {
2517 Fmax(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2518}
2519
2521 LiftoffRegister src) {
2522 Sxtl(dst.fp().V2D(), src.fp().V2S());
2523 Scvtf(dst.fp().V2D(), dst.fp().V2D());
2524}
2525
2527 LiftoffRegister src) {
2528 Uxtl(dst.fp().V2D(), src.fp().V2S());
2529 Ucvtf(dst.fp().V2D(), dst.fp().V2D());
2530}
2531
2532void LiftoffAssembler::emit_f64x2_promote_low_f32x4(LiftoffRegister dst,
2533 LiftoffRegister src) {
2534 Fcvtl(dst.fp().V2D(), src.fp().V2S());
2535}
2536
2537void LiftoffAssembler::emit_f32x4_splat(LiftoffRegister dst,
2538 LiftoffRegister src) {
2539 Dup(dst.fp().V4S(), src.fp().S(), 0);
2540}
2541
2542void LiftoffAssembler::emit_f32x4_extract_lane(LiftoffRegister dst,
2543 LiftoffRegister lhs,
2544 uint8_t imm_lane_idx) {
2545 Mov(dst.fp().S(), lhs.fp().V4S(), imm_lane_idx);
2546}
2547
2548void LiftoffAssembler::emit_f32x4_replace_lane(LiftoffRegister dst,
2549 LiftoffRegister src1,
2550 LiftoffRegister src2,
2551 uint8_t imm_lane_idx) {
2552 if (dst != src1) {
2553 Mov(dst.fp().V4S(), src1.fp().V4S());
2554 }
2555 Mov(dst.fp().V4S(), imm_lane_idx, src2.fp().V4S(), 0);
2556}
2557
2558void LiftoffAssembler::emit_f32x4_abs(LiftoffRegister dst,
2559 LiftoffRegister src) {
2560 Fabs(dst.fp().V4S(), src.fp().V4S());
2561}
2562
2563void LiftoffAssembler::emit_f32x4_neg(LiftoffRegister dst,
2564 LiftoffRegister src) {
2565 Fneg(dst.fp().V4S(), src.fp().V4S());
2566}
2567
2568void LiftoffAssembler::emit_f32x4_sqrt(LiftoffRegister dst,
2569 LiftoffRegister src) {
2570 Fsqrt(dst.fp().V4S(), src.fp().V4S());
2571}
2572
2573bool LiftoffAssembler::emit_f32x4_ceil(LiftoffRegister dst,
2574 LiftoffRegister src) {
2575 Frintp(dst.fp().V4S(), src.fp().V4S());
2576 return true;
2577}
2578
2579bool LiftoffAssembler::emit_f32x4_floor(LiftoffRegister dst,
2580 LiftoffRegister src) {
2581 Frintm(dst.fp().V4S(), src.fp().V4S());
2582 return true;
2583}
2584
2585bool LiftoffAssembler::emit_f32x4_trunc(LiftoffRegister dst,
2586 LiftoffRegister src) {
2587 Frintz(dst.fp().V4S(), src.fp().V4S());
2588 return true;
2589}
2590
2591bool LiftoffAssembler::emit_f32x4_nearest_int(LiftoffRegister dst,
2592 LiftoffRegister src) {
2593 Frintn(dst.fp().V4S(), src.fp().V4S());
2594 return true;
2595}
2596
2597void LiftoffAssembler::emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs,
2598 LiftoffRegister rhs) {
2599 Fadd(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2600}
2601
2602void LiftoffAssembler::emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs,
2603 LiftoffRegister rhs) {
2604 Fsub(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2605}
2606
2607void LiftoffAssembler::emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs,
2608 LiftoffRegister rhs) {
2609 Fmul(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2610}
2611
2612void LiftoffAssembler::emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs,
2613 LiftoffRegister rhs) {
2614 Fdiv(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2615}
2616
2617void LiftoffAssembler::emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs,
2618 LiftoffRegister rhs) {
2619 Fmin(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2620}
2621
2622void LiftoffAssembler::emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs,
2623 LiftoffRegister rhs) {
2624 Fmax(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2625}
2626
2627void LiftoffAssembler::emit_f32x4_relaxed_min(LiftoffRegister dst,
2628 LiftoffRegister lhs,
2629 LiftoffRegister rhs) {
2630 Fmin(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2631}
2632
2633void LiftoffAssembler::emit_f32x4_relaxed_max(LiftoffRegister dst,
2634 LiftoffRegister lhs,
2635 LiftoffRegister rhs) {
2636 Fmax(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2637}
2638
2639void LiftoffAssembler::emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs,
2640 LiftoffRegister rhs) {
2641 UseScratchRegisterScope temps(this);
2642
2643 VRegister tmp = dst.fp();
2644 if (dst == lhs || dst == rhs) {
2645 tmp = temps.AcquireV(kFormat4S);
2646 }
2647
2648 Fcmgt(tmp.V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2649 Bsl(tmp.V16B(), rhs.fp().V16B(), lhs.fp().V16B());
2650
2651 if (dst == lhs || dst == rhs) {
2652 Mov(dst.fp().V4S(), tmp);
2653 }
2654}
2655
2656void LiftoffAssembler::emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs,
2657 LiftoffRegister rhs) {
2658 UseScratchRegisterScope temps(this);
2659
2660 VRegister tmp = dst.fp();
2661 if (dst == lhs || dst == rhs) {
2662 tmp = temps.AcquireV(kFormat4S);
2663 }
2664
2665 Fcmgt(tmp.V4S(), rhs.fp().V4S(), lhs.fp().V4S());
2666 Bsl(tmp.V16B(), rhs.fp().V16B(), lhs.fp().V16B());
2667
2668 if (dst == lhs || dst == rhs) {
2669 Mov(dst.fp().V4S(), tmp);
2670 }
2671}
2672
2673void LiftoffAssembler::emit_i64x2_splat(LiftoffRegister dst,
2674 LiftoffRegister src) {
2675 Dup(dst.fp().V2D(), src.gp().X());
2676}
2677
2678void LiftoffAssembler::emit_i64x2_extract_lane(LiftoffRegister dst,
2679 LiftoffRegister lhs,
2680 uint8_t imm_lane_idx) {
2681 Mov(dst.gp().X(), lhs.fp().V2D(), imm_lane_idx);
2682}
2683
2684void LiftoffAssembler::emit_i64x2_replace_lane(LiftoffRegister dst,
2685 LiftoffRegister src1,
2686 LiftoffRegister src2,
2687 uint8_t imm_lane_idx) {
2688 if (dst != src1) {
2689 Mov(dst.fp().V2D(), src1.fp().V2D());
2690 }
2691 Mov(dst.fp().V2D(), imm_lane_idx, src2.gp().X());
2692}
2693
2694void LiftoffAssembler::emit_i64x2_neg(LiftoffRegister dst,
2695 LiftoffRegister src) {
2696 Neg(dst.fp().V2D(), src.fp().V2D());
2697}
2698
2699void LiftoffAssembler::emit_i64x2_alltrue(LiftoffRegister dst,
2700 LiftoffRegister src) {
2701 I64x2AllTrue(dst.gp(), src.fp());
2702}
2703
2704void LiftoffAssembler::emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs,
2705 LiftoffRegister rhs) {
2707 this, dst.fp().V2D(), lhs.fp().V2D(), rhs.gp(), kFormat2D);
2708}
2709
2710void LiftoffAssembler::emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs,
2711 int32_t rhs) {
2712 Shl(dst.fp().V2D(), lhs.fp().V2D(), rhs & 63);
2713}
2714
2715void LiftoffAssembler::emit_i64x2_shr_s(LiftoffRegister dst,
2716 LiftoffRegister lhs,
2717 LiftoffRegister rhs) {
2720 this, dst.fp().V2D(), lhs.fp().V2D(), rhs.gp(), kFormat2D);
2721}
2722
2723void LiftoffAssembler::emit_i64x2_shri_s(LiftoffRegister dst,
2724 LiftoffRegister lhs, int32_t rhs) {
2726 this, dst.fp().V2D(), lhs.fp().V2D(), rhs);
2727}
2728
2729void LiftoffAssembler::emit_i64x2_shr_u(LiftoffRegister dst,
2730 LiftoffRegister lhs,
2731 LiftoffRegister rhs) {
2734 this, dst.fp().V2D(), lhs.fp().V2D(), rhs.gp(), kFormat2D);
2735}
2736
2737void LiftoffAssembler::emit_i64x2_shri_u(LiftoffRegister dst,
2738 LiftoffRegister lhs, int32_t rhs) {
2741 this, dst.fp().V2D(), lhs.fp().V2D(), rhs);
2742}
2743
2744void LiftoffAssembler::emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs,
2745 LiftoffRegister rhs) {
2746 Add(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2747}
2748
2749void LiftoffAssembler::emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs,
2750 LiftoffRegister rhs) {
2751 Sub(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
2752}
2753
2754void LiftoffAssembler::emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs,
2755 LiftoffRegister rhs) {
2756 UseScratchRegisterScope temps(this);
2757 VRegister tmp1 = temps.AcquireV(kFormat2D);
2758 VRegister tmp2 = temps.AcquireV(kFormat2D);
2759
2760 // Algorithm copied from code-generator-arm64.cc with minor modifications:
2761 // - 2 (max number of scratch registers in Liftoff) temporaries instead of 3
2762 // - 1 more Umull instruction to calculate | cg | ae |,
2763 // - so, we can no longer use Umlal in the last step, and use Add instead.
2764 // Refer to comments there for details.
2765 Xtn(tmp1.V2S(), lhs.fp().V2D());
2766 Xtn(tmp2.V2S(), rhs.fp().V2D());
2767 Umull(tmp1.V2D(), tmp1.V2S(), tmp2.V2S());
2768 Rev64(tmp2.V4S(), rhs.fp().V4S());
2769 Mul(tmp2.V4S(), tmp2.V4S(), lhs.fp().V4S());
2770 Addp(tmp2.V4S(), tmp2.V4S(), tmp2.V4S());
2771 Shll(dst.fp().V2D(), tmp2.V2S(), 32);
2772 Add(dst.fp().V2D(), dst.fp().V2D(), tmp1.V2D());
2773}
2774
2776 LiftoffRegister src1,
2777 LiftoffRegister src2) {
2778 Smull(dst.fp().V2D(), src1.fp().V2S(), src2.fp().V2S());
2779}
2780
2782 LiftoffRegister src1,
2783 LiftoffRegister src2) {
2784 Umull(dst.fp().V2D(), src1.fp().V2S(), src2.fp().V2S());
2785}
2786
2788 LiftoffRegister src1,
2789 LiftoffRegister src2) {
2790 Smull2(dst.fp().V2D(), src1.fp().V4S(), src2.fp().V4S());
2791}
2792
2794 LiftoffRegister src1,
2795 LiftoffRegister src2) {
2796 Umull2(dst.fp().V2D(), src1.fp().V4S(), src2.fp().V4S());
2797}
2798
2799void LiftoffAssembler::emit_i64x2_bitmask(LiftoffRegister dst,
2800 LiftoffRegister src) {
2801 I64x2BitMask(dst.gp(), src.fp());
2802}
2803
2805 LiftoffRegister src) {
2806 Sxtl(dst.fp().V2D(), src.fp().V2S());
2807}
2808
2810 LiftoffRegister src) {
2811 Sxtl2(dst.fp().V2D(), src.fp().V4S());
2812}
2813
2815 LiftoffRegister src) {
2816 Uxtl(dst.fp().V2D(), src.fp().V2S());
2817}
2818
2820 LiftoffRegister src) {
2821 Uxtl2(dst.fp().V2D(), src.fp().V4S());
2822}
2823
2824void LiftoffAssembler::emit_i32x4_splat(LiftoffRegister dst,
2825 LiftoffRegister src) {
2826 Dup(dst.fp().V4S(), src.gp().W());
2827}
2828
2829void LiftoffAssembler::emit_i32x4_extract_lane(LiftoffRegister dst,
2830 LiftoffRegister lhs,
2831 uint8_t imm_lane_idx) {
2832 Mov(dst.gp().W(), lhs.fp().V4S(), imm_lane_idx);
2833}
2834
2835void LiftoffAssembler::emit_i32x4_replace_lane(LiftoffRegister dst,
2836 LiftoffRegister src1,
2837 LiftoffRegister src2,
2838 uint8_t imm_lane_idx) {
2839 if (dst != src1) {
2840 Mov(dst.fp().V4S(), src1.fp().V4S());
2841 }
2842 Mov(dst.fp().V4S(), imm_lane_idx, src2.gp().W());
2843}
2844
2845void LiftoffAssembler::emit_i32x4_neg(LiftoffRegister dst,
2846 LiftoffRegister src) {
2847 Neg(dst.fp().V4S(), src.fp().V4S());
2848}
2849
2850void LiftoffAssembler::emit_i32x4_alltrue(LiftoffRegister dst,
2851 LiftoffRegister src) {
2852 liftoff::EmitAllTrue(this, dst, src, kFormat4S);
2853}
2854
2855void LiftoffAssembler::emit_i32x4_bitmask(LiftoffRegister dst,
2856 LiftoffRegister src) {
2857 I32x4BitMask(dst.gp(), src.fp());
2858}
2859
2860void LiftoffAssembler::emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs,
2861 LiftoffRegister rhs) {
2863 this, dst.fp().V4S(), lhs.fp().V4S(), rhs.gp(), kFormat4S);
2864}
2865
2866void LiftoffAssembler::emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs,
2867 int32_t rhs) {
2868 Shl(dst.fp().V4S(), lhs.fp().V4S(), rhs & 31);
2869}
2870
2871void LiftoffAssembler::emit_i32x4_shr_s(LiftoffRegister dst,
2872 LiftoffRegister lhs,
2873 LiftoffRegister rhs) {
2876 this, dst.fp().V4S(), lhs.fp().V4S(), rhs.gp(), kFormat4S);
2877}
2878
2879void LiftoffAssembler::emit_i32x4_shri_s(LiftoffRegister dst,
2880 LiftoffRegister lhs, int32_t rhs) {
2882 this, dst.fp().V4S(), lhs.fp().V4S(), rhs);
2883}
2884
2885void LiftoffAssembler::emit_i32x4_shr_u(LiftoffRegister dst,
2886 LiftoffRegister lhs,
2887 LiftoffRegister rhs) {
2890 this, dst.fp().V4S(), lhs.fp().V4S(), rhs.gp(), kFormat4S);
2891}
2892
2893void LiftoffAssembler::emit_i32x4_shri_u(LiftoffRegister dst,
2894 LiftoffRegister lhs, int32_t rhs) {
2897 this, dst.fp().V4S(), lhs.fp().V4S(), rhs);
2898}
2899
2900void LiftoffAssembler::emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs,
2901 LiftoffRegister rhs) {
2902 Add(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2903}
2904
2905void LiftoffAssembler::emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs,
2906 LiftoffRegister rhs) {
2907 Sub(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2908}
2909
2910void LiftoffAssembler::emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs,
2911 LiftoffRegister rhs) {
2912 Mul(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2913}
2914
2915void LiftoffAssembler::emit_i32x4_min_s(LiftoffRegister dst,
2916 LiftoffRegister lhs,
2917 LiftoffRegister rhs) {
2918 Smin(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2919}
2920
2921void LiftoffAssembler::emit_i32x4_min_u(LiftoffRegister dst,
2922 LiftoffRegister lhs,
2923 LiftoffRegister rhs) {
2924 Umin(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2925}
2926
2927void LiftoffAssembler::emit_i32x4_max_s(LiftoffRegister dst,
2928 LiftoffRegister lhs,
2929 LiftoffRegister rhs) {
2930 Smax(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2931}
2932
2933void LiftoffAssembler::emit_i32x4_max_u(LiftoffRegister dst,
2934 LiftoffRegister lhs,
2935 LiftoffRegister rhs) {
2936 Umax(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
2937}
2938
2939void LiftoffAssembler::emit_i32x4_dot_i16x8_s(LiftoffRegister dst,
2940 LiftoffRegister lhs,
2941 LiftoffRegister rhs) {
2942 UseScratchRegisterScope scope(this);
2943 VRegister tmp1 = scope.AcquireV(kFormat4S);
2944 VRegister tmp2 = scope.AcquireV(kFormat4S);
2945 Smull(tmp1, lhs.fp().V4H(), rhs.fp().V4H());
2946 Smull2(tmp2, lhs.fp().V8H(), rhs.fp().V8H());
2947 Addp(dst.fp().V4S(), tmp1, tmp2);
2948}
2949
2951 LiftoffRegister src) {
2952 Saddlp(dst.fp().V4S(), src.fp().V8H());
2953}
2954
2956 LiftoffRegister src) {
2957 Uaddlp(dst.fp().V4S(), src.fp().V8H());
2958}
2959
2961 LiftoffRegister src1,
2962 LiftoffRegister src2) {
2963 Smull(dst.fp().V4S(), src1.fp().V4H(), src2.fp().V4H());
2964}
2965
2967 LiftoffRegister src1,
2968 LiftoffRegister src2) {
2969 Umull(dst.fp().V4S(), src1.fp().V4H(), src2.fp().V4H());
2970}
2971
2973 LiftoffRegister src1,
2974 LiftoffRegister src2) {
2975 Smull2(dst.fp().V4S(), src1.fp().V8H(), src2.fp().V8H());
2976}
2977
2979 LiftoffRegister src1,
2980 LiftoffRegister src2) {
2981 Umull2(dst.fp().V4S(), src1.fp().V8H(), src2.fp().V8H());
2982}
2983
2984void LiftoffAssembler::emit_i16x8_splat(LiftoffRegister dst,
2985 LiftoffRegister src) {
2986 Dup(dst.fp().V8H(), src.gp().W());
2987}
2988
2989void LiftoffAssembler::emit_i16x8_extract_lane_u(LiftoffRegister dst,
2990 LiftoffRegister lhs,
2991 uint8_t imm_lane_idx) {
2992 Umov(dst.gp().W(), lhs.fp().V8H(), imm_lane_idx);
2993}
2994
2995void LiftoffAssembler::emit_i16x8_extract_lane_s(LiftoffRegister dst,
2996 LiftoffRegister lhs,
2997 uint8_t imm_lane_idx) {
2998 Smov(dst.gp().W(), lhs.fp().V8H(), imm_lane_idx);
2999}
3000
3001void LiftoffAssembler::emit_i16x8_replace_lane(LiftoffRegister dst,
3002 LiftoffRegister src1,
3003 LiftoffRegister src2,
3004 uint8_t imm_lane_idx) {
3005 if (dst != src1) {
3006 Mov(dst.fp().V8H(), src1.fp().V8H());
3007 }
3008 Mov(dst.fp().V8H(), imm_lane_idx, src2.gp().W());
3009}
3010
3011void LiftoffAssembler::emit_i16x8_neg(LiftoffRegister dst,
3012 LiftoffRegister src) {
3013 Neg(dst.fp().V8H(), src.fp().V8H());
3014}
3015
3016void LiftoffAssembler::emit_i16x8_alltrue(LiftoffRegister dst,
3017 LiftoffRegister src) {
3018 liftoff::EmitAllTrue(this, dst, src, kFormat8H);
3019}
3020
3021void LiftoffAssembler::emit_i16x8_bitmask(LiftoffRegister dst,
3022 LiftoffRegister src) {
3023 I16x8BitMask(dst.gp(), src.fp());
3024}
3025
3026void LiftoffAssembler::emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs,
3027 LiftoffRegister rhs) {
3029 this, dst.fp().V8H(), lhs.fp().V8H(), rhs.gp(), kFormat8H);
3030}
3031
3032void LiftoffAssembler::emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs,
3033 int32_t rhs) {
3034 Shl(dst.fp().V8H(), lhs.fp().V8H(), rhs & 15);
3035}
3036
3037void LiftoffAssembler::emit_i16x8_shr_s(LiftoffRegister dst,
3038 LiftoffRegister lhs,
3039 LiftoffRegister rhs) {
3042 this, dst.fp().V8H(), lhs.fp().V8H(), rhs.gp(), kFormat8H);
3043}
3044
3045void LiftoffAssembler::emit_i16x8_shri_s(LiftoffRegister dst,
3046 LiftoffRegister lhs, int32_t rhs) {
3048 this, dst.fp().V8H(), lhs.fp().V8H(), rhs);
3049}
3050
3051void LiftoffAssembler::emit_i16x8_shr_u(LiftoffRegister dst,
3052 LiftoffRegister lhs,
3053 LiftoffRegister rhs) {
3056 this, dst.fp().V8H(), lhs.fp().V8H(), rhs.gp(), kFormat8H);
3057}
3058
3059void LiftoffAssembler::emit_i16x8_shri_u(LiftoffRegister dst,
3060 LiftoffRegister lhs, int32_t rhs) {
3063 this, dst.fp().V8H(), lhs.fp().V8H(), rhs);
3064}
3065
3066void LiftoffAssembler::emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs,
3067 LiftoffRegister rhs) {
3068 Add(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3069}
3070
3071void LiftoffAssembler::emit_i16x8_add_sat_s(LiftoffRegister dst,
3072 LiftoffRegister lhs,
3073 LiftoffRegister rhs) {
3074 Sqadd(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3075}
3076
3077void LiftoffAssembler::emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs,
3078 LiftoffRegister rhs) {
3079 Sub(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3080}
3081
3082void LiftoffAssembler::emit_i16x8_sub_sat_s(LiftoffRegister dst,
3083 LiftoffRegister lhs,
3084 LiftoffRegister rhs) {
3085 Sqsub(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3086}
3087
3088void LiftoffAssembler::emit_i16x8_sub_sat_u(LiftoffRegister dst,
3089 LiftoffRegister lhs,
3090 LiftoffRegister rhs) {
3091 Uqsub(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3092}
3093
3094void LiftoffAssembler::emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs,
3095 LiftoffRegister rhs) {
3096 Mul(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3097}
3098
3099void LiftoffAssembler::emit_i16x8_add_sat_u(LiftoffRegister dst,
3100 LiftoffRegister lhs,
3101 LiftoffRegister rhs) {
3102 Uqadd(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3103}
3104
3105void LiftoffAssembler::emit_i16x8_min_s(LiftoffRegister dst,
3106 LiftoffRegister lhs,
3107 LiftoffRegister rhs) {
3108 Smin(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3109}
3110
3111void LiftoffAssembler::emit_i16x8_min_u(LiftoffRegister dst,
3112 LiftoffRegister lhs,
3113 LiftoffRegister rhs) {
3114 Umin(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3115}
3116
3117void LiftoffAssembler::emit_i16x8_max_s(LiftoffRegister dst,
3118 LiftoffRegister lhs,
3119 LiftoffRegister rhs) {
3120 Smax(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3121}
3122
3123void LiftoffAssembler::emit_i16x8_max_u(LiftoffRegister dst,
3124 LiftoffRegister lhs,
3125 LiftoffRegister rhs) {
3126 Umax(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3127}
3128
3129void LiftoffAssembler::emit_i8x16_shuffle(LiftoffRegister dst,
3130 LiftoffRegister lhs,
3131 LiftoffRegister rhs,
3132 const uint8_t shuffle[16],
3133 bool is_swizzle) {
3134 VRegister src1 = lhs.fp();
3135 VRegister src2 = rhs.fp();
3136 VRegister temp = dst.fp();
3137 if (dst == lhs || dst == rhs) {
3138 // dst overlaps with lhs or rhs, so we need a temporary.
3139 temp = GetUnusedRegister(kFpReg, LiftoffRegList{lhs, rhs}).fp();
3140 }
3141
3142 UseScratchRegisterScope scope(this);
3143
3144 if (src1 != src2 && !AreConsecutive(src1, src2)) {
3145 // Tbl needs consecutive registers, which our scratch registers are.
3146 src1 = scope.AcquireV(kFormat16B);
3147 src2 = scope.AcquireV(kFormat16B);
3148 DCHECK(AreConsecutive(src1, src2));
3149 Mov(src1.Q(), lhs.fp().Q());
3150 Mov(src2.Q(), rhs.fp().Q());
3151 }
3152
3153 int64_t imms[2] = {0, 0};
3154 for (int i = 7; i >= 0; i--) {
3155 imms[0] = (imms[0] << 8) | (shuffle[i]);
3156 imms[1] = (imms[1] << 8) | (shuffle[i + 8]);
3157 }
3158 DCHECK_EQ(0, (imms[0] | imms[1]) &
3159 (lhs == rhs ? 0xF0F0F0F0F0F0F0F0 : 0xE0E0E0E0E0E0E0E0));
3160
3161 Movi(temp.V16B(), imms[1], imms[0]);
3162
3163 if (src1 == src2) {
3164 Tbl(dst.fp().V16B(), src1.V16B(), temp.V16B());
3165 } else {
3166 Tbl(dst.fp().V16B(), src1.V16B(), src2.V16B(), temp.V16B());
3167 }
3168}
3169
3170void LiftoffAssembler::emit_i8x16_popcnt(LiftoffRegister dst,
3171 LiftoffRegister src) {
3172 Cnt(dst.fp().V16B(), src.fp().V16B());
3173}
3174
3175void LiftoffAssembler::emit_i8x16_splat(LiftoffRegister dst,
3176 LiftoffRegister src) {
3177 Dup(dst.fp().V16B(), src.gp().W());
3178}
3179
3180void LiftoffAssembler::emit_i8x16_extract_lane_u(LiftoffRegister dst,
3181 LiftoffRegister lhs,
3182 uint8_t imm_lane_idx) {
3183 Umov(dst.gp().W(), lhs.fp().V16B(), imm_lane_idx);
3184}
3185
3186void LiftoffAssembler::emit_i8x16_extract_lane_s(LiftoffRegister dst,
3187 LiftoffRegister lhs,
3188 uint8_t imm_lane_idx) {
3189 Smov(dst.gp().W(), lhs.fp().V16B(), imm_lane_idx);
3190}
3191
3192void LiftoffAssembler::emit_i8x16_replace_lane(LiftoffRegister dst,
3193 LiftoffRegister src1,
3194 LiftoffRegister src2,
3195 uint8_t imm_lane_idx) {
3196 if (dst != src1) {
3197 Mov(dst.fp().V16B(), src1.fp().V16B());
3198 }
3199 Mov(dst.fp().V16B(), imm_lane_idx, src2.gp().W());
3200}
3201
3202void LiftoffAssembler::emit_i8x16_neg(LiftoffRegister dst,
3203 LiftoffRegister src) {
3204 Neg(dst.fp().V16B(), src.fp().V16B());
3205}
3206
3207void LiftoffAssembler::emit_v128_anytrue(LiftoffRegister dst,
3208 LiftoffRegister src) {
3209 liftoff::EmitAnyTrue(this, dst, src);
3210}
3211
3212void LiftoffAssembler::emit_i8x16_alltrue(LiftoffRegister dst,
3213 LiftoffRegister src) {
3214 liftoff::EmitAllTrue(this, dst, src, kFormat16B);
3215}
3216
3217void LiftoffAssembler::emit_i8x16_bitmask(LiftoffRegister dst,
3218 LiftoffRegister src) {
3219 VRegister temp = NoVReg;
3220
3221 if (CpuFeatures::IsSupported(PMULL1Q)) {
3222 temp = GetUnusedRegister(kFpReg, LiftoffRegList{src}).fp();
3223 }
3224
3225 I8x16BitMask(dst.gp(), src.fp(), temp);
3226}
3227
3228void LiftoffAssembler::emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs,
3229 LiftoffRegister rhs) {
3231 this, dst.fp().V16B(), lhs.fp().V16B(), rhs.gp(), kFormat16B);
3232}
3233
3234void LiftoffAssembler::emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs,
3235 int32_t rhs) {
3236 Shl(dst.fp().V16B(), lhs.fp().V16B(), rhs & 7);
3237}
3238
3239void LiftoffAssembler::emit_i8x16_shr_s(LiftoffRegister dst,
3240 LiftoffRegister lhs,
3241 LiftoffRegister rhs) {
3244 this, dst.fp().V16B(), lhs.fp().V16B(), rhs.gp(), kFormat16B);
3245}
3246
3247void LiftoffAssembler::emit_i8x16_shri_s(LiftoffRegister dst,
3248 LiftoffRegister lhs, int32_t rhs) {
3250 this, dst.fp().V16B(), lhs.fp().V16B(), rhs);
3251}
3252
3253void LiftoffAssembler::emit_i8x16_shr_u(LiftoffRegister dst,
3254 LiftoffRegister lhs,
3255 LiftoffRegister rhs) {
3258 this, dst.fp().V16B(), lhs.fp().V16B(), rhs.gp(), kFormat16B);
3259}
3260
3261void LiftoffAssembler::emit_i8x16_shri_u(LiftoffRegister dst,
3262 LiftoffRegister lhs, int32_t rhs) {
3265 this, dst.fp().V16B(), lhs.fp().V16B(), rhs);
3266}
3267
3268void LiftoffAssembler::emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs,
3269 LiftoffRegister rhs) {
3270 Add(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3271}
3272
3273void LiftoffAssembler::emit_i8x16_add_sat_s(LiftoffRegister dst,
3274 LiftoffRegister lhs,
3275 LiftoffRegister rhs) {
3276 Sqadd(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3277}
3278
3279void LiftoffAssembler::emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs,
3280 LiftoffRegister rhs) {
3281 Sub(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3282}
3283
3284void LiftoffAssembler::emit_i8x16_sub_sat_s(LiftoffRegister dst,
3285 LiftoffRegister lhs,
3286 LiftoffRegister rhs) {
3287 Sqsub(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3288}
3289
3290void LiftoffAssembler::emit_i8x16_sub_sat_u(LiftoffRegister dst,
3291 LiftoffRegister lhs,
3292 LiftoffRegister rhs) {
3293 Uqsub(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3294}
3295
3296void LiftoffAssembler::emit_i8x16_add_sat_u(LiftoffRegister dst,
3297 LiftoffRegister lhs,
3298 LiftoffRegister rhs) {
3299 Uqadd(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3300}
3301
3302void LiftoffAssembler::emit_i8x16_min_s(LiftoffRegister dst,
3303 LiftoffRegister lhs,
3304 LiftoffRegister rhs) {
3305 Smin(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3306}
3307
3308void LiftoffAssembler::emit_i8x16_min_u(LiftoffRegister dst,
3309 LiftoffRegister lhs,
3310 LiftoffRegister rhs) {
3311 Umin(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3312}
3313
3314void LiftoffAssembler::emit_i8x16_max_s(LiftoffRegister dst,
3315 LiftoffRegister lhs,
3316 LiftoffRegister rhs) {
3317 Smax(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3318}
3319
3320void LiftoffAssembler::emit_i8x16_max_u(LiftoffRegister dst,
3321 LiftoffRegister lhs,
3322 LiftoffRegister rhs) {
3323 Umax(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3324}
3325
3326void LiftoffAssembler::emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs,
3327 LiftoffRegister rhs) {
3328 Cmeq(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3329}
3330
3331void LiftoffAssembler::emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs,
3332 LiftoffRegister rhs) {
3333 Cmeq(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3334 Mvn(dst.fp().V16B(), dst.fp().V16B());
3335}
3336
3337void LiftoffAssembler::emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
3338 LiftoffRegister rhs) {
3339 Cmgt(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3340}
3341
3342void LiftoffAssembler::emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
3343 LiftoffRegister rhs) {
3344 Cmhi(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3345}
3346
3347void LiftoffAssembler::emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
3348 LiftoffRegister rhs) {
3349 Cmge(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3350}
3351
3352void LiftoffAssembler::emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
3353 LiftoffRegister rhs) {
3354 Cmhs(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3355}
3356
3357void LiftoffAssembler::emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs,
3358 LiftoffRegister rhs) {
3359 Cmeq(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3360}
3361
3362void LiftoffAssembler::emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs,
3363 LiftoffRegister rhs) {
3364 Cmeq(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3365 Mvn(dst.fp().V8H(), dst.fp().V8H());
3366}
3367
3368void LiftoffAssembler::emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
3369 LiftoffRegister rhs) {
3370 Cmgt(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3371}
3372
3373void LiftoffAssembler::emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
3374 LiftoffRegister rhs) {
3375 Cmhi(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3376}
3377
3378void LiftoffAssembler::emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
3379 LiftoffRegister rhs) {
3380 Cmge(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3381}
3382
3383void LiftoffAssembler::emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
3384 LiftoffRegister rhs) {
3385 Cmhs(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3386}
3387
3388void LiftoffAssembler::emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs,
3389 LiftoffRegister rhs) {
3390 Cmeq(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3391}
3392
3393void LiftoffAssembler::emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs,
3394 LiftoffRegister rhs) {
3395 Cmeq(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3396 Mvn(dst.fp().V4S(), dst.fp().V4S());
3397}
3398
3399void LiftoffAssembler::emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
3400 LiftoffRegister rhs) {
3401 Cmgt(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3402}
3403
3404void LiftoffAssembler::emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
3405 LiftoffRegister rhs) {
3406 Cmhi(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3407}
3408
3409void LiftoffAssembler::emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
3410 LiftoffRegister rhs) {
3411 Cmge(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3412}
3413
3414void LiftoffAssembler::emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
3415 LiftoffRegister rhs) {
3416 Cmhs(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3417}
3418
3419void LiftoffAssembler::emit_i64x2_eq(LiftoffRegister dst, LiftoffRegister lhs,
3420 LiftoffRegister rhs) {
3421 Cmeq(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
3422}
3423
3424void LiftoffAssembler::emit_i64x2_ne(LiftoffRegister dst, LiftoffRegister lhs,
3425 LiftoffRegister rhs) {
3426 Cmeq(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
3427 Mvn(dst.fp().V2D(), dst.fp().V2D());
3428}
3429
3430void LiftoffAssembler::emit_i64x2_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
3431 LiftoffRegister rhs) {
3432 Cmgt(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
3433}
3434
3435void LiftoffAssembler::emit_i64x2_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
3436 LiftoffRegister rhs) {
3437 Cmge(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
3438}
3439
3440void LiftoffAssembler::emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs,
3441 LiftoffRegister rhs) {
3442 Fcmeq(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3443}
3444
3445void LiftoffAssembler::emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs,
3446 LiftoffRegister rhs) {
3447 Fcmeq(dst.fp().V4S(), lhs.fp().V4S(), rhs.fp().V4S());
3448 Mvn(dst.fp().V4S(), dst.fp().V4S());
3449}
3450
3451void LiftoffAssembler::emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs,
3452 LiftoffRegister rhs) {
3453 Fcmgt(dst.fp().V4S(), rhs.fp().V4S(), lhs.fp().V4S());
3454}
3455
3456void LiftoffAssembler::emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs,
3457 LiftoffRegister rhs) {
3458 Fcmge(dst.fp().V4S(), rhs.fp().V4S(), lhs.fp().V4S());
3459}
3460
3461void LiftoffAssembler::emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs,
3462 LiftoffRegister rhs) {
3463 Fcmeq(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
3464}
3465
3466void LiftoffAssembler::emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs,
3467 LiftoffRegister rhs) {
3468 Fcmeq(dst.fp().V2D(), lhs.fp().V2D(), rhs.fp().V2D());
3469 Mvn(dst.fp().V2D(), dst.fp().V2D());
3470}
3471
3472void LiftoffAssembler::emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs,
3473 LiftoffRegister rhs) {
3474 Fcmgt(dst.fp().V2D(), rhs.fp().V2D(), lhs.fp().V2D());
3475}
3476
3477void LiftoffAssembler::emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs,
3478 LiftoffRegister rhs) {
3479 Fcmge(dst.fp().V2D(), rhs.fp().V2D(), lhs.fp().V2D());
3480}
3481
3482void LiftoffAssembler::emit_s128_const(LiftoffRegister dst,
3483 const uint8_t imms[16]) {
3484 uint64_t vals[2];
3485 memcpy(vals, imms, sizeof(vals));
3486 Movi(dst.fp().V16B(), vals[1], vals[0]);
3487}
3488
3489void LiftoffAssembler::emit_s128_not(LiftoffRegister dst, LiftoffRegister src) {
3490 Mvn(dst.fp().V16B(), src.fp().V16B());
3491}
3492
3493void LiftoffAssembler::emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs,
3494 LiftoffRegister rhs) {
3495 And(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3496}
3497
3498void LiftoffAssembler::emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs,
3499 LiftoffRegister rhs) {
3500 Orr(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3501}
3502
3503void LiftoffAssembler::emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs,
3504 LiftoffRegister rhs) {
3505 Eor(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3506}
3507
3508void LiftoffAssembler::emit_s128_select(LiftoffRegister dst,
3509 LiftoffRegister src1,
3510 LiftoffRegister src2,
3511 LiftoffRegister mask) {
3512 if (dst != mask) {
3513 Mov(dst.fp().V16B(), mask.fp().V16B());
3514 }
3515 Bsl(dst.fp().V16B(), src1.fp().V16B(), src2.fp().V16B());
3516}
3517
3518void LiftoffAssembler::emit_i32x4_sconvert_f32x4(LiftoffRegister dst,
3519 LiftoffRegister src) {
3520 Fcvtzs(dst.fp().V4S(), src.fp().V4S());
3521}
3522
3523void LiftoffAssembler::emit_i32x4_uconvert_f32x4(LiftoffRegister dst,
3524 LiftoffRegister src) {
3525 Fcvtzu(dst.fp().V4S(), src.fp().V4S());
3526}
3527
3528void LiftoffAssembler::emit_f32x4_sconvert_i32x4(LiftoffRegister dst,
3529 LiftoffRegister src) {
3530 Scvtf(dst.fp().V4S(), src.fp().V4S());
3531}
3532
3533void LiftoffAssembler::emit_f32x4_uconvert_i32x4(LiftoffRegister dst,
3534 LiftoffRegister src) {
3535 Ucvtf(dst.fp().V4S(), src.fp().V4S());
3536}
3537
3538void LiftoffAssembler::emit_f32x4_demote_f64x2_zero(LiftoffRegister dst,
3539 LiftoffRegister src) {
3540 Fcvtn(dst.fp().V2S(), src.fp().V2D());
3541}
3542
3543void LiftoffAssembler::emit_i8x16_sconvert_i16x8(LiftoffRegister dst,
3544 LiftoffRegister lhs,
3545 LiftoffRegister rhs) {
3546 UseScratchRegisterScope temps(this);
3547 VRegister tmp = temps.AcquireV(kFormat8H);
3548 VRegister right = rhs.fp().V8H();
3549 if (dst == rhs) {
3550 Mov(tmp, right);
3551 right = tmp;
3552 }
3553 Sqxtn(dst.fp().V8B(), lhs.fp().V8H());
3554 Sqxtn2(dst.fp().V16B(), right);
3555}
3556
3557void LiftoffAssembler::emit_i8x16_uconvert_i16x8(LiftoffRegister dst,
3558 LiftoffRegister lhs,
3559 LiftoffRegister rhs) {
3560 UseScratchRegisterScope temps(this);
3561 VRegister tmp = temps.AcquireV(kFormat8H);
3562 VRegister right = rhs.fp().V8H();
3563 if (dst == rhs) {
3564 Mov(tmp, right);
3565 right = tmp;
3566 }
3567 Sqxtun(dst.fp().V8B(), lhs.fp().V8H());
3568 Sqxtun2(dst.fp().V16B(), right);
3569}
3570
3571void LiftoffAssembler::emit_i16x8_sconvert_i32x4(LiftoffRegister dst,
3572 LiftoffRegister lhs,
3573 LiftoffRegister rhs) {
3574 UseScratchRegisterScope temps(this);
3575 VRegister tmp = temps.AcquireV(kFormat4S);
3576 VRegister right = rhs.fp().V4S();
3577 if (dst == rhs) {
3578 Mov(tmp, right);
3579 right = tmp;
3580 }
3581 Sqxtn(dst.fp().V4H(), lhs.fp().V4S());
3582 Sqxtn2(dst.fp().V8H(), right);
3583}
3584
3585void LiftoffAssembler::emit_i16x8_uconvert_i32x4(LiftoffRegister dst,
3586 LiftoffRegister lhs,
3587 LiftoffRegister rhs) {
3588 UseScratchRegisterScope temps(this);
3589 VRegister tmp = temps.AcquireV(kFormat4S);
3590 VRegister right = rhs.fp().V4S();
3591 if (dst == rhs) {
3592 Mov(tmp, right);
3593 right = tmp;
3594 }
3595 Sqxtun(dst.fp().V4H(), lhs.fp().V4S());
3596 Sqxtun2(dst.fp().V8H(), right);
3597}
3598
3600 LiftoffRegister src) {
3601 Sxtl(dst.fp().V8H(), src.fp().V8B());
3602}
3603
3605 LiftoffRegister src) {
3606 Sxtl2(dst.fp().V8H(), src.fp().V16B());
3607}
3608
3610 LiftoffRegister src) {
3611 Uxtl(dst.fp().V8H(), src.fp().V8B());
3612}
3613
3615 LiftoffRegister src) {
3616 Uxtl2(dst.fp().V8H(), src.fp().V16B());
3617}
3618
3620 LiftoffRegister src) {
3621 Sxtl(dst.fp().V4S(), src.fp().V4H());
3622}
3623
3625 LiftoffRegister src) {
3626 Sxtl2(dst.fp().V4S(), src.fp().V8H());
3627}
3628
3630 LiftoffRegister src) {
3631 Uxtl(dst.fp().V4S(), src.fp().V4H());
3632}
3633
3635 LiftoffRegister src) {
3636 Uxtl2(dst.fp().V4S(), src.fp().V8H());
3637}
3638
3640 LiftoffRegister src) {
3641 Fcvtzs(dst.fp().V2D(), src.fp().V2D());
3642 Sqxtn(dst.fp().V2S(), dst.fp().V2D());
3643}
3644
3646 LiftoffRegister src) {
3647 Fcvtzu(dst.fp().V2D(), src.fp().V2D());
3648 Uqxtn(dst.fp().V2S(), dst.fp().V2D());
3649}
3650
3651void LiftoffAssembler::emit_s128_and_not(LiftoffRegister dst,
3652 LiftoffRegister lhs,
3653 LiftoffRegister rhs) {
3654 Bic(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3655}
3656
3658 LiftoffRegister lhs,
3659 LiftoffRegister rhs) {
3660 Urhadd(dst.fp().V16B(), lhs.fp().V16B(), rhs.fp().V16B());
3661}
3662
3664 LiftoffRegister lhs,
3665 LiftoffRegister rhs) {
3666 Urhadd(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3667}
3668
3669void LiftoffAssembler::emit_i8x16_abs(LiftoffRegister dst,
3670 LiftoffRegister src) {
3671 Abs(dst.fp().V16B(), src.fp().V16B());
3672}
3673
3674void LiftoffAssembler::emit_i16x8_abs(LiftoffRegister dst,
3675 LiftoffRegister src) {
3676 Abs(dst.fp().V8H(), src.fp().V8H());
3677}
3678
3680 LiftoffRegister src) {
3681 Saddlp(dst.fp().V8H(), src.fp().V16B());
3682}
3683
3685 LiftoffRegister src) {
3686 Uaddlp(dst.fp().V8H(), src.fp().V16B());
3687}
3688
3690 LiftoffRegister src1,
3691 LiftoffRegister src2) {
3692 Smull(dst.fp().V8H(), src1.fp().V8B(), src2.fp().V8B());
3693}
3694
3696 LiftoffRegister src1,
3697 LiftoffRegister src2) {
3698 Umull(dst.fp().V8H(), src1.fp().V8B(), src2.fp().V8B());
3699}
3700
3702 LiftoffRegister src1,
3703 LiftoffRegister src2) {
3704 Smull2(dst.fp().V8H(), src1.fp().V16B(), src2.fp().V16B());
3705}
3706
3708 LiftoffRegister src1,
3709 LiftoffRegister src2) {
3710 Umull2(dst.fp().V8H(), src1.fp().V16B(), src2.fp().V16B());
3711}
3712
3713void LiftoffAssembler::emit_i16x8_q15mulr_sat_s(LiftoffRegister dst,
3714 LiftoffRegister src1,
3715 LiftoffRegister src2) {
3716 Sqrdmulh(dst.fp().V8H(), src1.fp().V8H(), src2.fp().V8H());
3717}
3718
3719void LiftoffAssembler::emit_i16x8_relaxed_q15mulr_s(LiftoffRegister dst,
3720 LiftoffRegister src1,
3721 LiftoffRegister src2) {
3722 Sqrdmulh(dst.fp().V8H(), src1.fp().V8H(), src2.fp().V8H());
3723}
3724
3725void LiftoffAssembler::emit_i16x8_dot_i8x16_i7x16_s(LiftoffRegister dst,
3726 LiftoffRegister lhs,
3727 LiftoffRegister rhs) {
3728 UseScratchRegisterScope scope(this);
3729 VRegister tmp1 = scope.AcquireV(kFormat8H);
3730 VRegister tmp2 = scope.AcquireV(kFormat8H);
3731 Smull(tmp1, lhs.fp().V8B(), rhs.fp().V8B());
3732 Smull2(tmp2, lhs.fp().V16B(), rhs.fp().V16B());
3733 Addp(dst.fp().V8H(), tmp1, tmp2);
3734}
3735
3737 LiftoffRegister lhs,
3738 LiftoffRegister rhs,
3739 LiftoffRegister acc) {
3740 UseScratchRegisterScope scope(this);
3741 VRegister tmp1 = scope.AcquireV(kFormat8H);
3742 VRegister tmp2 = scope.AcquireV(kFormat8H);
3743 Smull(tmp1, lhs.fp().V8B(), rhs.fp().V8B());
3744 Smull2(tmp2, lhs.fp().V16B(), rhs.fp().V16B());
3745 Addp(tmp1, tmp1, tmp2);
3746 Saddlp(tmp1.V4S(), tmp1);
3747 Add(dst.fp().V4S(), tmp1.V4S(), acc.fp().V4S());
3748}
3749
3750void LiftoffAssembler::emit_i32x4_abs(LiftoffRegister dst,
3751 LiftoffRegister src) {
3752 Abs(dst.fp().V4S(), src.fp().V4S());
3753}
3754
3755void LiftoffAssembler::emit_i64x2_abs(LiftoffRegister dst,
3756 LiftoffRegister src) {
3757 Abs(dst.fp().V2D(), src.fp().V2D());
3758}
3759
3760#define EMIT_QFMOP(instr, format) \
3761 if (dst == src3) { \
3762 instr(dst.fp().V##format(), src1.fp().V##format(), src2.fp().V##format()); \
3763 } else if (dst != src1 && dst != src2) { \
3764 Mov(dst.fp().V##format(), src3.fp().V##format()); \
3765 instr(dst.fp().V##format(), src1.fp().V##format(), src2.fp().V##format()); \
3766 } else { \
3767 DCHECK(dst == src1 || dst == src2); \
3768 UseScratchRegisterScope temps(this); \
3769 VRegister tmp = temps.AcquireV(kFormat##format); \
3770 Mov(tmp, src3.fp().V##format()); \
3771 instr(tmp, src1.fp().V##format(), src2.fp().V##format()); \
3772 Mov(dst.fp().V##format(), tmp); \
3773 }
3774
3775bool LiftoffAssembler::emit_f16x8_qfma(LiftoffRegister dst,
3776 LiftoffRegister src1,
3777 LiftoffRegister src2,
3778 LiftoffRegister src3) {
3779 if (!CpuFeatures::IsSupported(FP16)) {
3780 return false;
3781 }
3782 EMIT_QFMOP(Fmla, 8H);
3783 return true;
3784}
3785
3786bool LiftoffAssembler::emit_f16x8_qfms(LiftoffRegister dst,
3787 LiftoffRegister src1,
3788 LiftoffRegister src2,
3789 LiftoffRegister src3) {
3790 if (!CpuFeatures::IsSupported(FP16)) {
3791 return false;
3792 }
3793 EMIT_QFMOP(Fmls, 8H);
3794 return true;
3795}
3796
3797void LiftoffAssembler::emit_f32x4_qfma(LiftoffRegister dst,
3798 LiftoffRegister src1,
3799 LiftoffRegister src2,
3800 LiftoffRegister src3) {
3801 EMIT_QFMOP(Fmla, 4S);
3802}
3803
3804void LiftoffAssembler::emit_f32x4_qfms(LiftoffRegister dst,
3805 LiftoffRegister src1,
3806 LiftoffRegister src2,
3807 LiftoffRegister src3) {
3808 EMIT_QFMOP(Fmls, 4S);
3809}
3810
3811void LiftoffAssembler::emit_f64x2_qfma(LiftoffRegister dst,
3812 LiftoffRegister src1,
3813 LiftoffRegister src2,
3814 LiftoffRegister src3) {
3815 EMIT_QFMOP(Fmla, 2D);
3816}
3817
3818void LiftoffAssembler::emit_f64x2_qfms(LiftoffRegister dst,
3819 LiftoffRegister src1,
3820 LiftoffRegister src2,
3821 LiftoffRegister src3) {
3822 EMIT_QFMOP(Fmls, 2D);
3823}
3824
3825#undef EMIT_QFMOP
3826
3827bool LiftoffAssembler::emit_f16x8_splat(LiftoffRegister dst,
3828 LiftoffRegister src) {
3829 if (!CpuFeatures::IsSupported(FP16)) {
3830 return false;
3831 }
3832 Fcvt(dst.fp().H(), src.fp().S());
3833 Dup(dst.fp().V8H(), dst.fp().H(), 0);
3834 return true;
3835}
3836
3837bool LiftoffAssembler::emit_f16x8_extract_lane(LiftoffRegister dst,
3838 LiftoffRegister lhs,
3839 uint8_t imm_lane_idx) {
3840 if (!CpuFeatures::IsSupported(FP16)) {
3841 return false;
3842 }
3843 Mov(dst.fp().H(), lhs.fp().V8H(), imm_lane_idx);
3844 Fcvt(dst.fp().S(), dst.fp().H());
3845 return true;
3846}
3847
3848bool LiftoffAssembler::emit_f16x8_replace_lane(LiftoffRegister dst,
3849 LiftoffRegister src1,
3850 LiftoffRegister src2,
3851 uint8_t imm_lane_idx) {
3852 if (!CpuFeatures::IsSupported(FP16)) {
3853 return false;
3854 }
3855 if (dst != src1) {
3856 Mov(dst.fp().V8H(), src1.fp().V8H());
3857 }
3858 UseScratchRegisterScope temps(this);
3859
3860 VRegister tmp = temps.AcquireV(kFormat8H);
3861 Fcvt(tmp.H(), src2.fp().S());
3862 Mov(dst.fp().V8H(), imm_lane_idx, tmp.V8H(), 0);
3863 return true;
3864}
3865
3866bool LiftoffAssembler::emit_f16x8_abs(LiftoffRegister dst,
3867 LiftoffRegister src) {
3868 if (!CpuFeatures::IsSupported(FP16)) {
3869 return false;
3870 }
3871 Fabs(dst.fp().V8H(), src.fp().V8H());
3872 return true;
3873}
3874
3875bool LiftoffAssembler::emit_f16x8_neg(LiftoffRegister dst,
3876 LiftoffRegister src) {
3877 if (!CpuFeatures::IsSupported(FP16)) {
3878 return false;
3879 }
3880 Fneg(dst.fp().V8H(), src.fp().V8H());
3881 return true;
3882}
3883
3884bool LiftoffAssembler::emit_f16x8_sqrt(LiftoffRegister dst,
3885 LiftoffRegister src) {
3886 if (!CpuFeatures::IsSupported(FP16)) {
3887 return false;
3888 }
3889 Fsqrt(dst.fp().V8H(), src.fp().V8H());
3890 return true;
3891}
3892
3893bool LiftoffAssembler::emit_f16x8_ceil(LiftoffRegister dst,
3894 LiftoffRegister src) {
3895 if (!CpuFeatures::IsSupported(FP16)) {
3896 return false;
3897 }
3898 Frintp(dst.fp().V8H(), src.fp().V8H());
3899 return true;
3900}
3901
3902bool LiftoffAssembler::emit_f16x8_floor(LiftoffRegister dst,
3903 LiftoffRegister src) {
3904 if (!CpuFeatures::IsSupported(FP16)) {
3905 return false;
3906 }
3907 Frintm(dst.fp().V8H(), src.fp().V8H());
3908 return true;
3909}
3910
3911bool LiftoffAssembler::emit_f16x8_trunc(LiftoffRegister dst,
3912 LiftoffRegister src) {
3913 if (!CpuFeatures::IsSupported(FP16)) {
3914 return false;
3915 }
3916 Frintz(dst.fp().V8H(), src.fp().V8H());
3917 return true;
3918}
3919
3920bool LiftoffAssembler::emit_f16x8_nearest_int(LiftoffRegister dst,
3921 LiftoffRegister src) {
3922 if (!CpuFeatures::IsSupported(FP16)) {
3923 return false;
3924 }
3925 Frintn(dst.fp().V8H(), src.fp().V8H());
3926 return true;
3927}
3928
3929bool LiftoffAssembler::emit_f16x8_eq(LiftoffRegister dst, LiftoffRegister lhs,
3930 LiftoffRegister rhs) {
3931 if (!CpuFeatures::IsSupported(FP16)) {
3932 return false;
3933 }
3934 Fcmeq(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3935 return true;
3936}
3937
3938bool LiftoffAssembler::emit_f16x8_ne(LiftoffRegister dst, LiftoffRegister lhs,
3939 LiftoffRegister rhs) {
3940 if (!CpuFeatures::IsSupported(FP16)) {
3941 return false;
3942 }
3943 Fcmeq(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3944 Mvn(dst.fp().V8H(), dst.fp().V8H());
3945 return true;
3946}
3947
3948bool LiftoffAssembler::emit_f16x8_lt(LiftoffRegister dst, LiftoffRegister lhs,
3949 LiftoffRegister rhs) {
3950 if (!CpuFeatures::IsSupported(FP16)) {
3951 return false;
3952 }
3953 Fcmgt(dst.fp().V8H(), rhs.fp().V8H(), lhs.fp().V8H());
3954 return true;
3955}
3956
3957bool LiftoffAssembler::emit_f16x8_le(LiftoffRegister dst, LiftoffRegister lhs,
3958 LiftoffRegister rhs) {
3959 if (!CpuFeatures::IsSupported(FP16)) {
3960 return false;
3961 }
3962 Fcmge(dst.fp().V8H(), rhs.fp().V8H(), lhs.fp().V8H());
3963 return true;
3964}
3965
3966bool LiftoffAssembler::emit_f16x8_add(LiftoffRegister dst, LiftoffRegister lhs,
3967 LiftoffRegister rhs) {
3968 if (!CpuFeatures::IsSupported(FP16)) {
3969 return false;
3970 }
3971 Fadd(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3972 return true;
3973}
3974
3975bool LiftoffAssembler::emit_f16x8_sub(LiftoffRegister dst, LiftoffRegister lhs,
3976 LiftoffRegister rhs) {
3977 if (!CpuFeatures::IsSupported(FP16)) {
3978 return false;
3979 }
3980 Fsub(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3981 return true;
3982}
3983
3984bool LiftoffAssembler::emit_f16x8_mul(LiftoffRegister dst, LiftoffRegister lhs,
3985 LiftoffRegister rhs) {
3986 if (!CpuFeatures::IsSupported(FP16)) {
3987 return false;
3988 }
3989 Fmul(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3990 return true;
3991}
3992
3993bool LiftoffAssembler::emit_f16x8_div(LiftoffRegister dst, LiftoffRegister lhs,
3994 LiftoffRegister rhs) {
3995 if (!CpuFeatures::IsSupported(FP16)) {
3996 return false;
3997 }
3998 Fdiv(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
3999 return true;
4000}
4001
4002bool LiftoffAssembler::emit_f16x8_min(LiftoffRegister dst, LiftoffRegister lhs,
4003 LiftoffRegister rhs) {
4004 if (!CpuFeatures::IsSupported(FP16)) {
4005 return false;
4006 }
4007 Fmin(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
4008 return true;
4009}
4010
4011bool LiftoffAssembler::emit_f16x8_max(LiftoffRegister dst, LiftoffRegister lhs,
4012 LiftoffRegister rhs) {
4013 if (!CpuFeatures::IsSupported(FP16)) {
4014 return false;
4015 }
4016 Fmax(dst.fp().V8H(), lhs.fp().V8H(), rhs.fp().V8H());
4017 return true;
4018}
4019
4020bool LiftoffAssembler::emit_f16x8_pmin(LiftoffRegister dst, LiftoffRegister lhs,
4021 LiftoffRegister rhs) {
4022 if (!CpuFeatures::IsSupported(FP16)) {
4023 return false;
4024 }
4025 UseScratchRegisterScope temps(this);
4026
4027 VRegister tmp = dst.fp();
4028 if (dst == lhs || dst == rhs) {
4029 tmp = temps.AcquireV(kFormat8H);
4030 }
4031
4032 Fcmgt(tmp.V8H(), lhs.fp().V8H(), rhs.fp().V8H());
4033 Bsl(tmp.V16B(), rhs.fp().V16B(), lhs.fp().V16B());
4034
4035 if (dst == lhs || dst == rhs) {
4036 Mov(dst.fp().V8H(), tmp);
4037 }
4038 return true;
4039}
4040
4041bool LiftoffAssembler::emit_f16x8_pmax(LiftoffRegister dst, LiftoffRegister lhs,
4042 LiftoffRegister rhs) {
4043 if (!CpuFeatures::IsSupported(FP16)) {
4044 return false;
4045 }
4046 UseScratchRegisterScope temps(this);
4047
4048 VRegister tmp = dst.fp();
4049 if (dst == lhs || dst == rhs) {
4050 tmp = temps.AcquireV(kFormat8H);
4051 }
4052
4053 Fcmgt(tmp.V8H(), rhs.fp().V8H(), lhs.fp().V8H());
4054 Bsl(tmp.V16B(), rhs.fp().V16B(), lhs.fp().V16B());
4055
4056 if (dst == lhs || dst == rhs) {
4057 Mov(dst.fp().V8H(), tmp);
4058 }
4059 return true;
4060}
4061
4062bool LiftoffAssembler::emit_i16x8_sconvert_f16x8(LiftoffRegister dst,
4063 LiftoffRegister src) {
4064 if (!CpuFeatures::IsSupported(FP16)) {
4065 return false;
4066 }
4067 Fcvtzs(dst.fp().V8H(), src.fp().V8H());
4068 return true;
4069}
4070
4071bool LiftoffAssembler::emit_i16x8_uconvert_f16x8(LiftoffRegister dst,
4072 LiftoffRegister src) {
4073 if (!CpuFeatures::IsSupported(FP16)) {
4074 return false;
4075 }
4076 Fcvtzu(dst.fp().V8H(), src.fp().V8H());
4077 return true;
4078}
4079
4080bool LiftoffAssembler::emit_f16x8_sconvert_i16x8(LiftoffRegister dst,
4081 LiftoffRegister src) {
4082 if (!CpuFeatures::IsSupported(FP16)) {
4083 return false;
4084 }
4085 Scvtf(dst.fp().V8H(), src.fp().V8H());
4086 return true;
4087}
4088
4089bool LiftoffAssembler::emit_f16x8_uconvert_i16x8(LiftoffRegister dst,
4090 LiftoffRegister src) {
4091 if (!CpuFeatures::IsSupported(FP16)) {
4092 return false;
4093 }
4094 Ucvtf(dst.fp().V8H(), src.fp().V8H());
4095 return true;
4096}
4097
4098bool LiftoffAssembler::emit_f16x8_demote_f32x4_zero(LiftoffRegister dst,
4099 LiftoffRegister src) {
4100 if (!CpuFeatures::IsSupported(FP16)) {
4101 return false;
4102 }
4103 Fcvtn(dst.fp().V4H(), src.fp().V4S());
4104 return true;
4105}
4106
4107bool LiftoffAssembler::emit_f16x8_demote_f64x2_zero(LiftoffRegister dst,
4108 LiftoffRegister src) {
4109 if (!CpuFeatures::IsSupported(FP16)) {
4110 return false;
4111 }
4112 // There is no vector f64 -> f16 conversion instruction,
4113 // so convert them by component using scalar version.
4114 // Convert high double to a temp reg first, because dst and src
4115 // can overlap.
4116 Mov(fp_scratch.D(), src.fp().V2D(), 1);
4117 Fcvt(fp_scratch.H(), fp_scratch.D());
4118
4119 Fcvt(dst.fp().H(), src.fp().D());
4120 Mov(dst.fp().V8H(), 1, fp_scratch.V8H(), 0);
4121 return true;
4122}
4123
4124bool LiftoffAssembler::emit_f32x4_promote_low_f16x8(LiftoffRegister dst,
4125 LiftoffRegister src) {
4126 if (!CpuFeatures::IsSupported(FP16)) {
4127 return false;
4128 }
4129 Fcvtl(dst.fp().V4S(), src.fp().V4H());
4130 return true;
4131}
4132
4134 return CpuFeatures::IsSupported(FP16);
4135}
4136
4138 Label* trap_label) {
4139 Cmp(index, max_index);
4140 B(trap_label, kUnsignedGreaterThanEqual);
4141}
4142
4143void LiftoffAssembler::StackCheck(Label* ool_code) {
4144 UseScratchRegisterScope temps(this);
4145 Register limit_address = temps.AcquireX();
4147 Cmp(sp, limit_address);
4148 B(ool_code, ls);
4149}
4150
4153}
4154
4155void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {
4156 PushCPURegList(liftoff::PadRegList(regs.GetGpList()));
4157 PushCPURegList(liftoff::PadVRegList(regs.GetFpList()));
4158}
4159
4160void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {
4161 PopCPURegList(liftoff::PadVRegList(regs.GetFpList()));
4162 PopCPURegList(liftoff::PadRegList(regs.GetGpList()));
4163}
4164
4166 SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills,
4167 LiftoffRegList ref_spills, int spill_offset) {
4168 LiftoffRegList fp_spills = all_spills & kFpCacheRegList;
4169 int spill_space_size = fp_spills.GetNumRegsSet() * kSimd128Size;
4170 LiftoffRegList gp_spills = all_spills & kGpCacheRegList;
4171 bool needs_padding = (gp_spills.GetNumRegsSet() & 1) != 0;
4172 if (needs_padding) {
4173 spill_space_size += kSystemPointerSize;
4174 ++spill_offset;
4175 }
4176 while (!gp_spills.is_empty()) {
4177 LiftoffRegister reg = gp_spills.GetLastRegSet();
4178 if (ref_spills.has(reg)) {
4179 safepoint.DefineTaggedStackSlot(spill_offset);
4180 }
4181 gp_spills.clear(reg);
4182 ++spill_offset;
4183 spill_space_size += kSystemPointerSize;
4184 }
4185 // Record the number of additional spill slots.
4186 RecordOolSpillSpaceSize(spill_space_size);
4187}
4188
4189void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {
4190 DropSlots(num_stack_slots);
4191 Ret();
4192}
4193
4195 const std::initializer_list<VarState> args, const LiftoffRegister* rets,
4196 ValueKind return_kind, ValueKind out_argument_kind, int stack_bytes,
4197 ExternalReference ext_ref) {
4198 // The stack pointer is required to be quadword aligned.
4199 int total_size = RoundUp(stack_bytes, kQuadWordSizeInBytes);
4200 // Reserve space in the stack.
4201 Claim(total_size, 1);
4202
4203 int arg_offset = 0;
4204 for (const VarState& arg : args) {
4205 liftoff::StoreToMemory(this, MemOperand{sp, arg_offset}, arg);
4206 arg_offset += value_kind_size(arg.kind());
4207 }
4208 DCHECK_LE(arg_offset, stack_bytes);
4209
4210 // Pass a pointer to the buffer with the arguments to the C function.
4211 Mov(x0, sp);
4212
4213 // Now call the C function.
4214 constexpr int kNumCCallArgs = 1;
4215 CallCFunction(ext_ref, kNumCCallArgs);
4216
4217 // Move return value to the right register.
4218 const LiftoffRegister* next_result_reg = rets;
4219 if (return_kind != kVoid) {
4220 constexpr Register kReturnReg = x0;
4221 if (kReturnReg != next_result_reg->gp()) {
4222 Move(*next_result_reg, LiftoffRegister(kReturnReg), return_kind);
4223 }
4224 ++next_result_reg;
4225 }
4226
4227 // Load potential output value from the buffer on the stack.
4228 if (out_argument_kind != kVoid) {
4229 if (out_argument_kind == kI16) {
4230 Ldrh(next_result_reg->gp(), MemOperand(sp));
4231 } else {
4232 Peek(liftoff::GetRegFromType(*next_result_reg, out_argument_kind), 0);
4233 }
4234 }
4235
4236 Drop(total_size, 1);
4237}
4238
4239void LiftoffAssembler::CallC(const std::initializer_list<VarState> args_list,
4240 ExternalReference ext_ref) {
4241 const int num_args = static_cast<int>(args_list.size());
4242 const VarState* const args = args_list.begin();
4243
4244 // Note: If we ever need more than eight arguments we would need to load the
4245 // stack arguments to registers (via LoadToRegister) in pairs of two, then use
4246 // Stp with MemOperand{sp, -2 * kSystemPointerSize, PreIndex} to push them to
4247 // the stack.
4248
4249 // Execute the parallel register move for register parameters.
4250 DCHECK_GE(arraysize(kCArgRegs), num_args);
4251 ParallelMove parallel_move{this};
4252 for (int reg_arg = 0; reg_arg < num_args; ++reg_arg) {
4253 parallel_move.LoadIntoRegister(LiftoffRegister{kCArgRegs[reg_arg]},
4254 args[reg_arg]);
4255 }
4256 parallel_move.Execute();
4257
4258 // Now call the C function.
4259 CallCFunction(ext_ref, num_args);
4260}
4261
4264}
4265
4268}
4269
4271 compiler::CallDescriptor* call_descriptor,
4272 Register target) {
4273 // For Arm64, we have more cache registers than wasm parameters. That means
4274 // that target will always be in a register.
4275 DCHECK(target.is_valid());
4276 CallWasmCodePointer(target, call_descriptor->signature_hash());
4277}
4278
4280 compiler::CallDescriptor* call_descriptor, Register target) {
4281 DCHECK(target.is_valid());
4282 // When control flow integrity is enabled, the target is a "bti c"
4283 // instruction, which enforces that the jump instruction is either a "blr", or
4284 // a "br" with x16 or x17 as its destination.
4285 UseScratchRegisterScope temps(this);
4286 temps.Exclude(x17);
4287 Mov(x17, target);
4288 CallWasmCodePointer(x17, call_descriptor->signature_hash(),
4290}
4291
4293 // A direct call to a builtin. Just encode the builtin index. This will be
4294 // patched at relocation.
4295 Call(static_cast<Address>(builtin), RelocInfo::WASM_STUB_CALL);
4296}
4297
4298void LiftoffAssembler::AllocateStackSlot(Register addr, uint32_t size) {
4299 // The stack pointer is required to be quadword aligned.
4300 size = RoundUp(size, kQuadWordSizeInBytes);
4301 Claim(size, 1);
4302 Mov(addr, sp);
4303}
4304
4305void LiftoffAssembler::DeallocateStackSlot(uint32_t size) {
4306 // The stack pointer is required to be quadword aligned.
4307 size = RoundUp(size, kQuadWordSizeInBytes);
4308 Drop(size, 1);
4309}
4310
4312
4314 DoubleRegister src,
4315 ValueKind kind) {
4316 Label not_nan;
4317 if (kind == kF32) {
4318 Fcmp(src.S(), src.S());
4319 B(eq, &not_nan); // x != x iff isnan(x)
4320 // If it's a NaN, it must be non-zero, so store that as the set value.
4321 Str(src.S(), MemOperand(dst));
4322 } else {
4324 Fcmp(src.D(), src.D());
4325 B(eq, &not_nan); // x != x iff isnan(x)
4326 // Double-precision NaNs must be non-zero in the most-significant 32
4327 // bits, so store that.
4328 St1(src.V4S(), 1, MemOperand(dst));
4329 }
4330 Bind(&not_nan);
4331}
4332
4334 LiftoffRegister src,
4335 Register tmp_gp,
4336 LiftoffRegister tmp_s128,
4337 ValueKind lane_kind) {
4338 DoubleRegister tmp_fp = tmp_s128.fp();
4339 if (lane_kind == kF32) {
4340 Fmaxv(tmp_fp.S(), src.fp().V4S());
4341 } else {
4342 DCHECK_EQ(lane_kind, kF64);
4343 Fmaxp(tmp_fp.D(), src.fp().V2D());
4344 }
4345 emit_store_nonzero_if_nan(dst, tmp_fp, lane_kind);
4346}
4347
4348void LiftoffAssembler::emit_store_nonzero(Register dst) {
4349 Str(dst, MemOperand(dst));
4350}
4351
4352void LiftoffStackSlots::Construct(int param_slots) {
4353 DCHECK_LT(0, slots_.size());
4354 // The stack pointer is required to be quadword aligned.
4355 asm_->Claim(RoundUp(param_slots, 2));
4356 for (auto& slot : slots_) {
4357 int poke_offset = slot.dst_slot_ * kSystemPointerSize;
4358 switch (slot.src_.loc()) {
4360 UseScratchRegisterScope temps(asm_);
4361 CPURegister scratch = liftoff::AcquireByType(&temps, slot.src_.kind());
4362 asm_->Ldr(scratch, liftoff::GetStackSlot(slot.src_offset_));
4363 asm_->Poke(scratch, poke_offset);
4364 break;
4365 }
4367 asm_->Poke(liftoff::GetRegFromType(slot.src_.reg(), slot.src_.kind()),
4368 poke_offset);
4369 break;
4371 DCHECK(slot.src_.kind() == kI32 || slot.src_.kind() == kI64);
4372 if (slot.src_.i32_const() == 0) {
4373 Register zero_reg = slot.src_.kind() == kI32 ? wzr : xzr;
4374 asm_->Poke(zero_reg, poke_offset);
4375 } else {
4376 UseScratchRegisterScope temps(asm_);
4377 Register scratch =
4378 slot.src_.kind() == kI32 ? temps.AcquireW() : temps.AcquireX();
4379 asm_->Mov(scratch, int64_t{slot.src_.i32_const()});
4380 asm_->Poke(scratch, poke_offset);
4381 }
4382 break;
4383 }
4384 }
4385}
4386
4387} // namespace v8::internal::wasm
4388
4389#endif // V8_WASM_BASELINE_ARM64_LIFTOFF_ASSEMBLER_ARM64_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
const AssemblerOptions & options() const
Definition assembler.h:339
void casal(const Register &rs, const Register &rt, const MemOperand &src)
static constexpr bool IsImmLSScaled(int64_t offset, unsigned size_log2)
static bool IsImmLSPair(int64_t offset, unsigned size)
void stlxrb(const Register &rs, const Register &rt, const Register &rn)
void b(int branch_offset, Condition cond=al, RelocInfo::Mode rmode=RelocInfo::NO_INFO)
void sxtw(const Register &rd, const Register &rn)
void ld1(const VRegister &vt, const MemOperand &src)
void sxtb(Register dst, Register src, int rotate=0, Condition cond=al)
void ldaxrh(const Register &rt, const Register &rn)
Instruction * InstructionAt(ptrdiff_t offset) const
void sxth(Register dst, Register src, int rotate=0, Condition cond=al)
static constexpr bool IsImmAddSub(int64_t immediate)
friend class UseScratchRegisterScope
void str(Register src, const MemOperand &dst, Condition cond=al)
void sub(Register dst, Register src1, const Operand &src2, SBit s=LeaveCC, Condition cond=al)
void ld1r(const VRegister &vt, const MemOperand &src)
void ldaxrb(const Register &rt, const Register &rn)
static constexpr bool IsImmLSUnscaled(int64_t offset)
void ldr(Register dst, const MemOperand &src, Condition cond=al)
void stlxr(const Register &rs, const Register &rt, const Register &rn)
void stp(const CPURegister &rt, const CPURegister &rt2, const MemOperand &dst)
void cbnz(const Register &rt, Label *label)
void AddSub(const Register &rd, const Register &rn, const Operand &operand, FlagsUpdate S, AddSubOp op)
void st1(const VRegister &vt, const MemOperand &src)
void AbortedCodeGeneration() override
void ldaxr(const Register &rt, const Register &rn)
void casalb(const Register &rs, const Register &rt, const MemOperand &src)
void casalh(const Register &rs, const Register &rt, const MemOperand &src)
void stlxrh(const Register &rs, const Register &rt, const Register &rn)
static constexpr CPURegister no_reg()
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 Mul(const Register &rd, const Register &rn, const Register &rm)
void Asr(const Register &rd, const Register &rn, unsigned shift)
void Msub(const Register &rd, const Register &rn, const Register &rm, const Register &ra)
void LoadStackLimit(Register destination, StackLimitKind kind)
void Fcvt(const VRegister &fd, const VRegister &fn)
void Call(Register target, Condition cond=al)
void St1(const VRegister &vt, const MemOperand &dst)
void Cmp(const Register &rn, int imm)
void Cmge(const VRegister &vd, const VRegister &vn, int imm)
void Drop(int count, Condition cond=al)
void Udiv(const Register &rd, const Register &rn, const Register &rm)
void Orr(const Register &rd, const Register &rn, const Operand &operand)
void Neg(const Register &rd, const Operand &operand)
void mov(Register rd, Register rj)
void Add(const Register &rd, const Register &rn, const Operand &operand)
void SmiUntag(Register reg, SBit s=LeaveCC)
void Fmin(const VRegister &fd, const VRegister &fn, const VRegister &fm)
void Bind(Label *label, BranchTargetIdentifier id=BranchTargetIdentifier::kNone)
void Bic(const VRegister &vd, const int imm8, const int left_shift=0)
void Fmax(const VRegister &fd, const VRegister &fn, const VRegister &fm)
void Fcvtzu(const Register &rd, const VRegister &fn)
void Fmov(VRegister fd, VRegister fn)
void I64x2AllTrue(Register dst, QwNeonRegister src)
void I32x4BitMask(Register dst, VRegister src)
void Lsr(const Register &rd, const Register &rn, unsigned shift)
void LoadTrustedPointerField(Register destination, MemOperand field_operand, IndirectPointerTag tag)
void JumpIfSmi(Register value, Label *smi_label)
void Smov(const Register &rd, const VRegister &vn, int vn_index)
void Poke(const CPURegister &src, const Operand &offset)
void Fabs(const VRegister &fd, const VRegister &fn)
void Smull(const Register &rd, const Register &rn, const Register &rm)
void AssertUnreachable(AbortReason reason) NOOP_UNLESS_DEBUG_CODE
void Clz(const Register &rd, const Register &rn)
void Peek(const CPURegister &dst, const Operand &offset)
void Uxtw(const Register &rd, const Register &rn)
void PopcntHelper(Register dst, Register src)
void Scvtf(const VRegister &fd, const Register &rn, unsigned fbits=0)
void Dmb(BarrierDomain domain, BarrierType type)
void Lsl(const Register &rd, const Register &rn, unsigned shift)
void SmiTag(Register reg, SBit s=LeaveCC)
void Umull(const Register &rd, const Register &rn, const Register &rm)
void Eor(const Register &rd, const Register &rn, const Operand &operand)
void Cmeq(const VRegister &vd, const VRegister &vn, int imm)
void Fdiv(const VRegister &fd, const VRegister &fn, const VRegister &fm)
void Ldr(const CPURegister &rt, const Operand &imm)
void Mov(const Register &rd, const Operand &operand, DiscardMoveMode discard_mode=kDontDiscardForSameWReg)
void And(Register dst, Register src1, const Operand &src2, Condition cond=al)
void Umov(const Register &rd, const VRegister &vn, int vn_index)
void Sdiv(const Register &rd, const Register &rn, const Register &rm)
void Jump(Register target, Condition cond=al)
void Fadd(const VRegister &fd, const VRegister &fn, const VRegister &fm)
void Fcmp(const VRegister &fn, const VRegister &fm)
void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg=false)
void Ucvtf(const VRegister &fd, const Register &rn, unsigned fbits=0)
void Csel(const Register &rd, const Register &rn, const Operand &operand, Condition cond)
void LoadTaggedField(const Register &destination, const MemOperand &field_operand)
void Rbit(const Register &rd, const Register &rn)
void LoadProtectedPointerField(Register destination, MemOperand field_operand)
void CheckPageFlag(Register object, int mask, Condition cc, Label *condition_met)
void PushCPURegList(CPURegList registers)
void Cmgt(const VRegister &vd, const VRegister &vn, int imm)
void Movi(const VRegister &vd, uint64_t imm, Shift shift=LSL, int shift_amount=0)
void I16x8BitMask(Register dst, VRegister src)
void Cset(const Register &rd, Condition cond)
int CallCFunction(ExternalReference function, int num_arguments, SetIsolateDataSlots set_isolate_data_slots=SetIsolateDataSlots::kYes, Label *return_label=nullptr)
void Dup(const VRegister &vd, const VRegister &vn, int index)
void I64x2BitMask(Register dst, QwNeonRegister src)
void Claim(int64_t count, uint64_t unit_size=kXRegSize)
void Tbl(const VRegister &vd, const VRegister &vn, const VRegister &vm)
void Fsub(const VRegister &fd, const VRegister &fn, const VRegister &fm)
void PopCPURegList(CPURegList registers)
void Fcvtzs(const Register &rd, const VRegister &fn)
void Mvn(const Register &rd, uint64_t imm)
void Ccmp(const Register &rn, const Operand &operand, StatusFlags nzcv, Condition cond)
void Sub(const Register &rd, const Register &rn, const Operand &operand)
void CallRecordWriteStubSaveRegisters(Register object, Operand offset, SaveFPRegsMode fp_mode, StubCallMode mode=StubCallMode::kCallBuiltinPointer)
void Fcsel(const VRegister &fd, const VRegister &fn, const VRegister &fm, Condition cond)
void I8x16BitMask(Register dst, VRegister src, VRegister temp=NoVReg)
void Cbnz(const Register &rt, Label *label)
void Cbz(const Register &rt, Label *label)
void Abs(const Register &rd, const Register &rm, Label *is_not_representable=nullptr, Label *is_representable=nullptr)
void Sxtw(const Register &rd, const Register &rn)
void Fmul(const VRegister &fd, const VRegister &fn, const VRegister &fm)
static constexpr MainThreadFlags kPointersToHereAreInterestingMask
static constexpr MainThreadFlags kPointersFromHereAreInterestingMask
constexpr void set(RegisterT reg)
constexpr unsigned Count() const
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
VRegister AcquireV(VectorFormat format)
static constexpr VRegister Create(int code, int size, int lane_count=1)
bool IsSameFormat(const VRegister &other) const
GetProtectedInstruction(LiftoffAssembler *assm, uint32_t *protected_instruction_pc)
void emit_i8x16_swizzle(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_uconvert_i32x4_low(LiftoffRegister dst, LiftoffRegister src)
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
base::SmallVector< Slot, 8 > slots_
static constexpr int ToTagged(int offset)
#define ATOMIC_BINOP_CASE(op, inst)
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
int start
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Label label
int32_t offset
TNode< Object > target
double remainder
ZoneVector< RpoNumber > & result
#define EMIT_QFMOP(instr, format)
LiftoffRegister reg
MovableLabel continuation
Register tmp
int pc_offset
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 AtomicBinop(LiftoffAssembler *lasm, Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, Binop op)
Register CalculateActualAddress(LiftoffAssembler *assm, UseScratchRegisterScope *temps, Register addr_reg, Register offset_reg, uintptr_t offset_imm, Register result_reg=no_reg)
void EmitSimdShiftRightImmediate(LiftoffAssembler *assm, VRegister dst, VRegister lhs, int32_t rhs)
void StoreToMemory(LiftoffAssembler *assm, MemOperand dst, const LiftoffAssembler::VarState &src)
void EmitAnyTrue(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister src)
CPURegister LoadToRegister(LiftoffAssembler *assm, UseScratchRegisterScope *temps, const LiftoffAssembler::VarState &src)
void Add(LiftoffAssembler *lasm, Register dst, Register lhs, Register rhs)
void EmitSimdShift(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
CPURegister AcquireByType(UseScratchRegisterScope *temps, ValueKind kind)
Register GetEffectiveAddress(LiftoffAssembler *assm, UseScratchRegisterScope *temps, Register addr, Register offset, uintptr_t offset_imm, bool i64_offset=false)
CPURegList PadVRegList(DoubleRegList list)
MemOperand GetMemOp(LiftoffAssembler *assm, UseScratchRegisterScope *temps, Register addr, Register offset, int32_t offset_imm, unsigned shift_amount=0)
CPURegister GetRegFromType(const LiftoffRegister &reg, ValueKind kind)
constexpr DoubleRegister kFpReturnRegisters[]
constexpr Register kGpParamRegisters[]
constexpr DoubleRegister kFpParamRegisters[]
constexpr Register kGpReturnRegisters[]
int declared_function_index(const WasmModule *module, int func_index)
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
V8_EXPORT_PRIVATE bool AreConsecutive(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg)
constexpr unsigned kQuadWordSizeInBytes
constexpr int H
constexpr int kSimd128Size
Definition globals.h:706
V8_EXPORT_PRIVATE int LaneCountFromFormat(VectorFormat vform)
DwVfpRegister DoubleRegister
kWasmInternalFunctionIndirectPointerTag instance_data
constexpr ShiftOp LSL
constexpr int B
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr uint8_t kInstrSizeLog2
constexpr int kSystemPointerSize
Definition globals.h:410
constexpr int S
const Instr kImmExceptionIsSwitchStackLimit
constexpr Register kReturnRegister0
constexpr bool SmiValuesAre31Bits()
constexpr int kInt32Size
Definition globals.h:401
constexpr VRegister NoVReg
unsigned LaneSizeInBitsFromFormat(VectorFormat vform)
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr Opcode SUB
constexpr AddrMode PostIndex
return value
Definition map-inl.h:893
constexpr int kXRegSizeInBits
constexpr uint8_t kInstrSize
constexpr int kQRegSizeInBits
constexpr Register kCArgRegs[]
constexpr int kXRegSizeLog2
constexpr int kXRegSize
VectorFormat ScalarFormatFromFormat(VectorFormat vform)
constexpr Register padreg
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#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
#define USE(...)
Definition macros.h:293
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
#define arraysize(array)
Definition macros.h:67
#define V8_LIKELY(condition)
Definition v8config.h:661