11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_WASM_BASELINE_IA32_LIFTOFF_ASSEMBLER_IA32_H_ 61cb0ef41Sopenharmony_ci#define V8_WASM_BASELINE_IA32_LIFTOFF_ASSEMBLER_IA32_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h" 91cb0ef41Sopenharmony_ci#include "src/codegen/assembler.h" 101cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk.h" 111cb0ef41Sopenharmony_ci#include "src/wasm/baseline/liftoff-assembler.h" 121cb0ef41Sopenharmony_ci#include "src/wasm/baseline/liftoff-register.h" 131cb0ef41Sopenharmony_ci#include "src/wasm/simd-shuffle.h" 141cb0ef41Sopenharmony_ci#include "src/wasm/value-type.h" 151cb0ef41Sopenharmony_ci#include "src/wasm/wasm-objects.h" 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cinamespace v8 { 181cb0ef41Sopenharmony_cinamespace internal { 191cb0ef41Sopenharmony_cinamespace wasm { 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci#define RETURN_FALSE_IF_MISSING_CPU_FEATURE(name) \ 221cb0ef41Sopenharmony_ci if (!CpuFeatures::IsSupported(name)) return false; \ 231cb0ef41Sopenharmony_ci CpuFeatureScope feature(this, name); 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_cinamespace liftoff { 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciinline constexpr Condition ToCondition(LiftoffCondition liftoff_cond) { 281cb0ef41Sopenharmony_ci switch (liftoff_cond) { 291cb0ef41Sopenharmony_ci case kEqual: 301cb0ef41Sopenharmony_ci return equal; 311cb0ef41Sopenharmony_ci case kUnequal: 321cb0ef41Sopenharmony_ci return not_equal; 331cb0ef41Sopenharmony_ci case kSignedLessThan: 341cb0ef41Sopenharmony_ci return less; 351cb0ef41Sopenharmony_ci case kSignedLessEqual: 361cb0ef41Sopenharmony_ci return less_equal; 371cb0ef41Sopenharmony_ci case kSignedGreaterThan: 381cb0ef41Sopenharmony_ci return greater; 391cb0ef41Sopenharmony_ci case kSignedGreaterEqual: 401cb0ef41Sopenharmony_ci return greater_equal; 411cb0ef41Sopenharmony_ci case kUnsignedLessThan: 421cb0ef41Sopenharmony_ci return below; 431cb0ef41Sopenharmony_ci case kUnsignedLessEqual: 441cb0ef41Sopenharmony_ci return below_equal; 451cb0ef41Sopenharmony_ci case kUnsignedGreaterThan: 461cb0ef41Sopenharmony_ci return above; 471cb0ef41Sopenharmony_ci case kUnsignedGreaterEqual: 481cb0ef41Sopenharmony_ci return above_equal; 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci// ebp-4 holds the stack marker, ebp-8 is the instance parameter. 531cb0ef41Sopenharmony_ciconstexpr int kInstanceOffset = 8; 541cb0ef41Sopenharmony_ciconstexpr int kFeedbackVectorOffset = 12; // ebp-12 is the feedback vector. 551cb0ef41Sopenharmony_ciconstexpr int kTierupBudgetOffset = 16; // ebp-16 is the tiering budget. 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ciinline Operand GetStackSlot(int offset) { return Operand(ebp, -offset); } 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciinline MemOperand GetHalfStackSlot(int offset, RegPairHalf half) { 601cb0ef41Sopenharmony_ci int32_t half_offset = 611cb0ef41Sopenharmony_ci half == kLowWord ? 0 : LiftoffAssembler::kStackSlotSize / 2; 621cb0ef41Sopenharmony_ci return Operand(offset > 0 ? ebp : esp, -offset + half_offset); 631cb0ef41Sopenharmony_ci} 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci// TODO(clemensb): Make this a constexpr variable once Operand is constexpr. 661cb0ef41Sopenharmony_ciinline Operand GetInstanceOperand() { return GetStackSlot(kInstanceOffset); } 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_cistatic constexpr LiftoffRegList kByteRegs = 691cb0ef41Sopenharmony_ci LiftoffRegList::FromBits<RegList{eax, ecx, edx}.bits()>(); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ciinline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base, 721cb0ef41Sopenharmony_ci int32_t offset, ValueKind kind) { 731cb0ef41Sopenharmony_ci Operand src(base, offset); 741cb0ef41Sopenharmony_ci switch (kind) { 751cb0ef41Sopenharmony_ci case kI32: 761cb0ef41Sopenharmony_ci case kOptRef: 771cb0ef41Sopenharmony_ci case kRef: 781cb0ef41Sopenharmony_ci case kRtt: 791cb0ef41Sopenharmony_ci assm->mov(dst.gp(), src); 801cb0ef41Sopenharmony_ci break; 811cb0ef41Sopenharmony_ci case kI64: 821cb0ef41Sopenharmony_ci assm->mov(dst.low_gp(), src); 831cb0ef41Sopenharmony_ci assm->mov(dst.high_gp(), Operand(base, offset + 4)); 841cb0ef41Sopenharmony_ci break; 851cb0ef41Sopenharmony_ci case kF32: 861cb0ef41Sopenharmony_ci assm->movss(dst.fp(), src); 871cb0ef41Sopenharmony_ci break; 881cb0ef41Sopenharmony_ci case kF64: 891cb0ef41Sopenharmony_ci assm->movsd(dst.fp(), src); 901cb0ef41Sopenharmony_ci break; 911cb0ef41Sopenharmony_ci case kS128: 921cb0ef41Sopenharmony_ci assm->movdqu(dst.fp(), src); 931cb0ef41Sopenharmony_ci break; 941cb0ef41Sopenharmony_ci default: 951cb0ef41Sopenharmony_ci UNREACHABLE(); 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci} 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ciinline void Store(LiftoffAssembler* assm, Register base, int32_t offset, 1001cb0ef41Sopenharmony_ci LiftoffRegister src, ValueKind kind) { 1011cb0ef41Sopenharmony_ci Operand dst(base, offset); 1021cb0ef41Sopenharmony_ci switch (kind) { 1031cb0ef41Sopenharmony_ci case kI32: 1041cb0ef41Sopenharmony_ci case kOptRef: 1051cb0ef41Sopenharmony_ci case kRef: 1061cb0ef41Sopenharmony_ci case kRtt: 1071cb0ef41Sopenharmony_ci assm->mov(dst, src.gp()); 1081cb0ef41Sopenharmony_ci break; 1091cb0ef41Sopenharmony_ci case kI64: 1101cb0ef41Sopenharmony_ci assm->mov(dst, src.low_gp()); 1111cb0ef41Sopenharmony_ci assm->mov(Operand(base, offset + 4), src.high_gp()); 1121cb0ef41Sopenharmony_ci break; 1131cb0ef41Sopenharmony_ci case kF32: 1141cb0ef41Sopenharmony_ci assm->movss(dst, src.fp()); 1151cb0ef41Sopenharmony_ci break; 1161cb0ef41Sopenharmony_ci case kF64: 1171cb0ef41Sopenharmony_ci assm->movsd(dst, src.fp()); 1181cb0ef41Sopenharmony_ci break; 1191cb0ef41Sopenharmony_ci case kS128: 1201cb0ef41Sopenharmony_ci assm->movdqu(dst, src.fp()); 1211cb0ef41Sopenharmony_ci break; 1221cb0ef41Sopenharmony_ci case kVoid: 1231cb0ef41Sopenharmony_ci case kBottom: 1241cb0ef41Sopenharmony_ci case kI8: 1251cb0ef41Sopenharmony_ci case kI16: 1261cb0ef41Sopenharmony_ci UNREACHABLE(); 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ciinline void push(LiftoffAssembler* assm, LiftoffRegister reg, ValueKind kind, 1311cb0ef41Sopenharmony_ci int padding = 0) { 1321cb0ef41Sopenharmony_ci switch (kind) { 1331cb0ef41Sopenharmony_ci case kI32: 1341cb0ef41Sopenharmony_ci case kRef: 1351cb0ef41Sopenharmony_ci case kOptRef: 1361cb0ef41Sopenharmony_ci case kRtt: 1371cb0ef41Sopenharmony_ci assm->AllocateStackSpace(padding); 1381cb0ef41Sopenharmony_ci assm->push(reg.gp()); 1391cb0ef41Sopenharmony_ci break; 1401cb0ef41Sopenharmony_ci case kI64: 1411cb0ef41Sopenharmony_ci assm->AllocateStackSpace(padding); 1421cb0ef41Sopenharmony_ci assm->push(reg.high_gp()); 1431cb0ef41Sopenharmony_ci assm->push(reg.low_gp()); 1441cb0ef41Sopenharmony_ci break; 1451cb0ef41Sopenharmony_ci case kF32: 1461cb0ef41Sopenharmony_ci assm->AllocateStackSpace(sizeof(float) + padding); 1471cb0ef41Sopenharmony_ci assm->movss(Operand(esp, 0), reg.fp()); 1481cb0ef41Sopenharmony_ci break; 1491cb0ef41Sopenharmony_ci case kF64: 1501cb0ef41Sopenharmony_ci assm->AllocateStackSpace(sizeof(double) + padding); 1511cb0ef41Sopenharmony_ci assm->movsd(Operand(esp, 0), reg.fp()); 1521cb0ef41Sopenharmony_ci break; 1531cb0ef41Sopenharmony_ci case kS128: 1541cb0ef41Sopenharmony_ci assm->AllocateStackSpace(sizeof(double) * 2 + padding); 1551cb0ef41Sopenharmony_ci assm->movdqu(Operand(esp, 0), reg.fp()); 1561cb0ef41Sopenharmony_ci break; 1571cb0ef41Sopenharmony_ci case kVoid: 1581cb0ef41Sopenharmony_ci case kBottom: 1591cb0ef41Sopenharmony_ci case kI8: 1601cb0ef41Sopenharmony_ci case kI16: 1611cb0ef41Sopenharmony_ci UNREACHABLE(); 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ciinline void SignExtendI32ToI64(Assembler* assm, LiftoffRegister reg) { 1661cb0ef41Sopenharmony_ci assm->mov(reg.high_gp(), reg.low_gp()); 1671cb0ef41Sopenharmony_ci assm->sar(reg.high_gp(), 31); 1681cb0ef41Sopenharmony_ci} 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci// Get a temporary byte register, using {candidate} if possible. 1711cb0ef41Sopenharmony_ci// Might spill, but always keeps status flags intact. 1721cb0ef41Sopenharmony_ciinline Register GetTmpByteRegister(LiftoffAssembler* assm, Register candidate) { 1731cb0ef41Sopenharmony_ci if (candidate.is_byte_register()) return candidate; 1741cb0ef41Sopenharmony_ci // {GetUnusedRegister()} may insert move instructions to spill registers to 1751cb0ef41Sopenharmony_ci // the stack. This is OK because {mov} does not change the status flags. 1761cb0ef41Sopenharmony_ci return assm->GetUnusedRegister(liftoff::kByteRegs).gp(); 1771cb0ef41Sopenharmony_ci} 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ciinline void MoveStackValue(LiftoffAssembler* assm, const Operand& src, 1801cb0ef41Sopenharmony_ci const Operand& dst) { 1811cb0ef41Sopenharmony_ci if (assm->cache_state()->has_unused_register(kGpReg)) { 1821cb0ef41Sopenharmony_ci Register tmp = assm->cache_state()->unused_register(kGpReg).gp(); 1831cb0ef41Sopenharmony_ci assm->mov(tmp, src); 1841cb0ef41Sopenharmony_ci assm->mov(dst, tmp); 1851cb0ef41Sopenharmony_ci } else { 1861cb0ef41Sopenharmony_ci // No free register, move via the stack. 1871cb0ef41Sopenharmony_ci assm->push(src); 1881cb0ef41Sopenharmony_ci assm->pop(dst); 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci} 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ciconstexpr DoubleRegister kScratchDoubleReg = xmm7; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ciconstexpr int kSubSpSize = 6; // 6 bytes for "sub esp, <imm32>" 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci} // namespace liftoff 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ciint LiftoffAssembler::PrepareStackFrame() { 1991cb0ef41Sopenharmony_ci int offset = pc_offset(); 2001cb0ef41Sopenharmony_ci // Next we reserve the memory for the whole stack frame. We do not know yet 2011cb0ef41Sopenharmony_ci // how big the stack frame will be so we just emit a placeholder instruction. 2021cb0ef41Sopenharmony_ci // PatchPrepareStackFrame will patch this in order to increase the stack 2031cb0ef41Sopenharmony_ci // appropriately. 2041cb0ef41Sopenharmony_ci sub_sp_32(0); 2051cb0ef41Sopenharmony_ci DCHECK_EQ(liftoff::kSubSpSize, pc_offset() - offset); 2061cb0ef41Sopenharmony_ci return offset; 2071cb0ef41Sopenharmony_ci} 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_civoid LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, 2101cb0ef41Sopenharmony_ci int stack_param_delta) { 2111cb0ef41Sopenharmony_ci // Push the return address and frame pointer to complete the stack frame. 2121cb0ef41Sopenharmony_ci push(Operand(ebp, 4)); 2131cb0ef41Sopenharmony_ci push(Operand(ebp, 0)); 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci // Shift the whole frame upwards. 2161cb0ef41Sopenharmony_ci Register scratch = eax; 2171cb0ef41Sopenharmony_ci push(scratch); 2181cb0ef41Sopenharmony_ci const int slot_count = num_callee_stack_params + 2; 2191cb0ef41Sopenharmony_ci for (int i = slot_count; i > 0; --i) { 2201cb0ef41Sopenharmony_ci mov(scratch, Operand(esp, i * 4)); 2211cb0ef41Sopenharmony_ci mov(Operand(ebp, (i - stack_param_delta - 1) * 4), scratch); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci pop(scratch); 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci // Set the new stack and frame pointers. 2261cb0ef41Sopenharmony_ci lea(esp, Operand(ebp, -stack_param_delta * 4)); 2271cb0ef41Sopenharmony_ci pop(ebp); 2281cb0ef41Sopenharmony_ci} 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_civoid LiftoffAssembler::AlignFrameSize() {} 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_civoid LiftoffAssembler::PatchPrepareStackFrame( 2331cb0ef41Sopenharmony_ci int offset, SafepointTableBuilder* safepoint_table_builder) { 2341cb0ef41Sopenharmony_ci // The frame_size includes the frame marker and the instance slot. Both are 2351cb0ef41Sopenharmony_ci // pushed as part of frame construction, so we don't need to allocate memory 2361cb0ef41Sopenharmony_ci // for them anymore. 2371cb0ef41Sopenharmony_ci int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize; 2381cb0ef41Sopenharmony_ci DCHECK_EQ(0, frame_size % kSystemPointerSize); 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci // We can't run out of space when patching, just pass anything big enough to 2411cb0ef41Sopenharmony_ci // not cause the assembler to try to grow the buffer. 2421cb0ef41Sopenharmony_ci constexpr int kAvailableSpace = 64; 2431cb0ef41Sopenharmony_ci Assembler patching_assembler( 2441cb0ef41Sopenharmony_ci AssemblerOptions{}, 2451cb0ef41Sopenharmony_ci ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace)); 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci if (V8_LIKELY(frame_size < 4 * KB)) { 2481cb0ef41Sopenharmony_ci // This is the standard case for small frames: just subtract from SP and be 2491cb0ef41Sopenharmony_ci // done with it. 2501cb0ef41Sopenharmony_ci patching_assembler.sub_sp_32(frame_size); 2511cb0ef41Sopenharmony_ci DCHECK_EQ(liftoff::kSubSpSize, patching_assembler.pc_offset()); 2521cb0ef41Sopenharmony_ci return; 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci // The frame size is bigger than 4KB, so we might overflow the available stack 2561cb0ef41Sopenharmony_ci // space if we first allocate the frame and then do the stack check (we will 2571cb0ef41Sopenharmony_ci // need some remaining stack space for throwing the exception). That's why we 2581cb0ef41Sopenharmony_ci // check the available stack space before we allocate the frame. To do this we 2591cb0ef41Sopenharmony_ci // replace the {__ sub(sp, framesize)} with a jump to OOL code that does this 2601cb0ef41Sopenharmony_ci // "extended stack check". 2611cb0ef41Sopenharmony_ci // 2621cb0ef41Sopenharmony_ci // The OOL code can simply be generated here with the normal assembler, 2631cb0ef41Sopenharmony_ci // because all other code generation, including OOL code, has already finished 2641cb0ef41Sopenharmony_ci // when {PatchPrepareStackFrame} is called. The function prologue then jumps 2651cb0ef41Sopenharmony_ci // to the current {pc_offset()} to execute the OOL code for allocating the 2661cb0ef41Sopenharmony_ci // large frame. 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci // Emit the unconditional branch in the function prologue (from {offset} to 2691cb0ef41Sopenharmony_ci // {pc_offset()}). 2701cb0ef41Sopenharmony_ci patching_assembler.jmp_rel(pc_offset() - offset); 2711cb0ef41Sopenharmony_ci DCHECK_GE(liftoff::kSubSpSize, patching_assembler.pc_offset()); 2721cb0ef41Sopenharmony_ci patching_assembler.Nop(liftoff::kSubSpSize - patching_assembler.pc_offset()); 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci // If the frame is bigger than the stack, we throw the stack overflow 2751cb0ef41Sopenharmony_ci // exception unconditionally. Thereby we can avoid the integer overflow 2761cb0ef41Sopenharmony_ci // check in the condition code. 2771cb0ef41Sopenharmony_ci RecordComment("OOL: stack check for large frame"); 2781cb0ef41Sopenharmony_ci Label continuation; 2791cb0ef41Sopenharmony_ci if (frame_size < FLAG_stack_size * 1024) { 2801cb0ef41Sopenharmony_ci // We do not have a scratch register, so pick any and push it first. 2811cb0ef41Sopenharmony_ci Register stack_limit = eax; 2821cb0ef41Sopenharmony_ci push(stack_limit); 2831cb0ef41Sopenharmony_ci mov(stack_limit, 2841cb0ef41Sopenharmony_ci FieldOperand(kWasmInstanceRegister, 2851cb0ef41Sopenharmony_ci WasmInstanceObject::kRealStackLimitAddressOffset)); 2861cb0ef41Sopenharmony_ci mov(stack_limit, Operand(stack_limit, 0)); 2871cb0ef41Sopenharmony_ci add(stack_limit, Immediate(frame_size)); 2881cb0ef41Sopenharmony_ci cmp(esp, stack_limit); 2891cb0ef41Sopenharmony_ci pop(stack_limit); 2901cb0ef41Sopenharmony_ci j(above_equal, &continuation, Label::kNear); 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci wasm_call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL); 2941cb0ef41Sopenharmony_ci // The call will not return; just define an empty safepoint. 2951cb0ef41Sopenharmony_ci safepoint_table_builder->DefineSafepoint(this); 2961cb0ef41Sopenharmony_ci AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap); 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci bind(&continuation); 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci // Now allocate the stack space. Note that this might do more than just 3011cb0ef41Sopenharmony_ci // decrementing the SP; consult {TurboAssembler::AllocateStackSpace}. 3021cb0ef41Sopenharmony_ci AllocateStackSpace(frame_size); 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci // Jump back to the start of the function, from {pc_offset()} to 3051cb0ef41Sopenharmony_ci // right after the reserved space for the {__ sub(sp, sp, framesize)} (which 3061cb0ef41Sopenharmony_ci // is a branch now). 3071cb0ef41Sopenharmony_ci int func_start_offset = offset + liftoff::kSubSpSize; 3081cb0ef41Sopenharmony_ci jmp_rel(func_start_offset - pc_offset()); 3091cb0ef41Sopenharmony_ci} 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_civoid LiftoffAssembler::FinishCode() {} 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_civoid LiftoffAssembler::AbortCompilation() {} 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci// static 3161cb0ef41Sopenharmony_ciconstexpr int LiftoffAssembler::StaticStackFrameSize() { 3171cb0ef41Sopenharmony_ci return liftoff::kTierupBudgetOffset; 3181cb0ef41Sopenharmony_ci} 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ciint LiftoffAssembler::SlotSizeForType(ValueKind kind) { 3211cb0ef41Sopenharmony_ci return value_kind_full_size(kind); 3221cb0ef41Sopenharmony_ci} 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_cibool LiftoffAssembler::NeedsAlignment(ValueKind kind) { 3251cb0ef41Sopenharmony_ci return is_reference(kind); 3261cb0ef41Sopenharmony_ci} 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value, 3291cb0ef41Sopenharmony_ci RelocInfo::Mode rmode) { 3301cb0ef41Sopenharmony_ci switch (value.type().kind()) { 3311cb0ef41Sopenharmony_ci case kI32: 3321cb0ef41Sopenharmony_ci TurboAssembler::Move(reg.gp(), Immediate(value.to_i32(), rmode)); 3331cb0ef41Sopenharmony_ci break; 3341cb0ef41Sopenharmony_ci case kI64: { 3351cb0ef41Sopenharmony_ci DCHECK(RelocInfo::IsNoInfo(rmode)); 3361cb0ef41Sopenharmony_ci int32_t low_word = value.to_i64(); 3371cb0ef41Sopenharmony_ci int32_t high_word = value.to_i64() >> 32; 3381cb0ef41Sopenharmony_ci TurboAssembler::Move(reg.low_gp(), Immediate(low_word)); 3391cb0ef41Sopenharmony_ci TurboAssembler::Move(reg.high_gp(), Immediate(high_word)); 3401cb0ef41Sopenharmony_ci break; 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci case kF32: 3431cb0ef41Sopenharmony_ci TurboAssembler::Move(reg.fp(), value.to_f32_boxed().get_bits()); 3441cb0ef41Sopenharmony_ci break; 3451cb0ef41Sopenharmony_ci case kF64: 3461cb0ef41Sopenharmony_ci TurboAssembler::Move(reg.fp(), value.to_f64_boxed().get_bits()); 3471cb0ef41Sopenharmony_ci break; 3481cb0ef41Sopenharmony_ci default: 3491cb0ef41Sopenharmony_ci UNREACHABLE(); 3501cb0ef41Sopenharmony_ci } 3511cb0ef41Sopenharmony_ci} 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadInstanceFromFrame(Register dst) { 3541cb0ef41Sopenharmony_ci mov(dst, liftoff::GetInstanceOperand()); 3551cb0ef41Sopenharmony_ci} 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadFromInstance(Register dst, Register instance, 3581cb0ef41Sopenharmony_ci int offset, int size) { 3591cb0ef41Sopenharmony_ci DCHECK_LE(0, offset); 3601cb0ef41Sopenharmony_ci Operand src{instance, offset}; 3611cb0ef41Sopenharmony_ci switch (size) { 3621cb0ef41Sopenharmony_ci case 1: 3631cb0ef41Sopenharmony_ci movzx_b(dst, src); 3641cb0ef41Sopenharmony_ci break; 3651cb0ef41Sopenharmony_ci case 4: 3661cb0ef41Sopenharmony_ci mov(dst, src); 3671cb0ef41Sopenharmony_ci break; 3681cb0ef41Sopenharmony_ci default: 3691cb0ef41Sopenharmony_ci UNIMPLEMENTED(); 3701cb0ef41Sopenharmony_ci } 3711cb0ef41Sopenharmony_ci} 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadTaggedPointerFromInstance(Register dst, 3741cb0ef41Sopenharmony_ci Register instance, 3751cb0ef41Sopenharmony_ci int offset) { 3761cb0ef41Sopenharmony_ci STATIC_ASSERT(kTaggedSize == kSystemPointerSize); 3771cb0ef41Sopenharmony_ci mov(dst, Operand{instance, offset}); 3781cb0ef41Sopenharmony_ci} 3791cb0ef41Sopenharmony_ci 3801cb0ef41Sopenharmony_civoid LiftoffAssembler::SpillInstance(Register instance) { 3811cb0ef41Sopenharmony_ci mov(liftoff::GetInstanceOperand(), instance); 3821cb0ef41Sopenharmony_ci} 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_civoid LiftoffAssembler::ResetOSRTarget() {} 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr, 3871cb0ef41Sopenharmony_ci Register offset_reg, 3881cb0ef41Sopenharmony_ci int32_t offset_imm, 3891cb0ef41Sopenharmony_ci LiftoffRegList pinned) { 3901cb0ef41Sopenharmony_ci DCHECK_GE(offset_imm, 0); 3911cb0ef41Sopenharmony_ci STATIC_ASSERT(kTaggedSize == kInt32Size); 3921cb0ef41Sopenharmony_ci Load(LiftoffRegister(dst), src_addr, offset_reg, 3931cb0ef41Sopenharmony_ci static_cast<uint32_t>(offset_imm), LoadType::kI32Load, pinned); 3941cb0ef41Sopenharmony_ci} 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr, 3971cb0ef41Sopenharmony_ci int32_t offset_imm) { 3981cb0ef41Sopenharmony_ci mov(dst, Operand(src_addr, offset_imm)); 3991cb0ef41Sopenharmony_ci} 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_civoid LiftoffAssembler::StoreTaggedPointer(Register dst_addr, 4021cb0ef41Sopenharmony_ci Register offset_reg, 4031cb0ef41Sopenharmony_ci int32_t offset_imm, 4041cb0ef41Sopenharmony_ci LiftoffRegister src, 4051cb0ef41Sopenharmony_ci LiftoffRegList pinned, 4061cb0ef41Sopenharmony_ci SkipWriteBarrier skip_write_barrier) { 4071cb0ef41Sopenharmony_ci DCHECK_GE(offset_imm, 0); 4081cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 4091cb0ef41Sopenharmony_ci STATIC_ASSERT(kTaggedSize == kInt32Size); 4101cb0ef41Sopenharmony_ci Operand dst_op = offset_reg == no_reg 4111cb0ef41Sopenharmony_ci ? Operand(dst_addr, offset_imm) 4121cb0ef41Sopenharmony_ci : Operand(dst_addr, offset_reg, times_1, offset_imm); 4131cb0ef41Sopenharmony_ci mov(dst_op, src.gp()); 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci if (skip_write_barrier || FLAG_disable_write_barriers) return; 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci Register scratch = pinned.set(GetUnusedRegister(kGpReg, pinned)).gp(); 4181cb0ef41Sopenharmony_ci Label write_barrier; 4191cb0ef41Sopenharmony_ci Label exit; 4201cb0ef41Sopenharmony_ci CheckPageFlag(dst_addr, scratch, 4211cb0ef41Sopenharmony_ci MemoryChunk::kPointersFromHereAreInterestingMask, not_zero, 4221cb0ef41Sopenharmony_ci &write_barrier, Label::kNear); 4231cb0ef41Sopenharmony_ci jmp(&exit, Label::kNear); 4241cb0ef41Sopenharmony_ci bind(&write_barrier); 4251cb0ef41Sopenharmony_ci JumpIfSmi(src.gp(), &exit, Label::kNear); 4261cb0ef41Sopenharmony_ci CheckPageFlag(src.gp(), scratch, 4271cb0ef41Sopenharmony_ci MemoryChunk::kPointersToHereAreInterestingMask, zero, &exit, 4281cb0ef41Sopenharmony_ci Label::kNear); 4291cb0ef41Sopenharmony_ci lea(scratch, dst_op); 4301cb0ef41Sopenharmony_ci CallRecordWriteStubSaveRegisters( 4311cb0ef41Sopenharmony_ci dst_addr, scratch, RememberedSetAction::kEmit, SaveFPRegsMode::kSave, 4321cb0ef41Sopenharmony_ci StubCallMode::kCallWasmRuntimeStub); 4331cb0ef41Sopenharmony_ci bind(&exit); 4341cb0ef41Sopenharmony_ci} 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_civoid LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, 4371cb0ef41Sopenharmony_ci Register offset_reg, uint32_t offset_imm, 4381cb0ef41Sopenharmony_ci LoadType type, LiftoffRegList pinned, 4391cb0ef41Sopenharmony_ci uint32_t* protected_load_pc, bool is_load_mem, 4401cb0ef41Sopenharmony_ci bool i64_offset) { 4411cb0ef41Sopenharmony_ci // Offsets >=2GB are statically OOB on 32-bit systems. 4421cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 4431cb0ef41Sopenharmony_ci DCHECK_EQ(type.value_type() == kWasmI64, dst.is_gp_pair()); 4441cb0ef41Sopenharmony_ci Operand src_op = offset_reg == no_reg 4451cb0ef41Sopenharmony_ci ? Operand(src_addr, offset_imm) 4461cb0ef41Sopenharmony_ci : Operand(src_addr, offset_reg, times_1, offset_imm); 4471cb0ef41Sopenharmony_ci if (protected_load_pc) *protected_load_pc = pc_offset(); 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci switch (type.value()) { 4501cb0ef41Sopenharmony_ci case LoadType::kI32Load8U: 4511cb0ef41Sopenharmony_ci movzx_b(dst.gp(), src_op); 4521cb0ef41Sopenharmony_ci break; 4531cb0ef41Sopenharmony_ci case LoadType::kI32Load8S: 4541cb0ef41Sopenharmony_ci movsx_b(dst.gp(), src_op); 4551cb0ef41Sopenharmony_ci break; 4561cb0ef41Sopenharmony_ci case LoadType::kI64Load8U: 4571cb0ef41Sopenharmony_ci movzx_b(dst.low_gp(), src_op); 4581cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); 4591cb0ef41Sopenharmony_ci break; 4601cb0ef41Sopenharmony_ci case LoadType::kI64Load8S: 4611cb0ef41Sopenharmony_ci movsx_b(dst.low_gp(), src_op); 4621cb0ef41Sopenharmony_ci liftoff::SignExtendI32ToI64(this, dst); 4631cb0ef41Sopenharmony_ci break; 4641cb0ef41Sopenharmony_ci case LoadType::kI32Load16U: 4651cb0ef41Sopenharmony_ci movzx_w(dst.gp(), src_op); 4661cb0ef41Sopenharmony_ci break; 4671cb0ef41Sopenharmony_ci case LoadType::kI32Load16S: 4681cb0ef41Sopenharmony_ci movsx_w(dst.gp(), src_op); 4691cb0ef41Sopenharmony_ci break; 4701cb0ef41Sopenharmony_ci case LoadType::kI64Load16U: 4711cb0ef41Sopenharmony_ci movzx_w(dst.low_gp(), src_op); 4721cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); 4731cb0ef41Sopenharmony_ci break; 4741cb0ef41Sopenharmony_ci case LoadType::kI64Load16S: 4751cb0ef41Sopenharmony_ci movsx_w(dst.low_gp(), src_op); 4761cb0ef41Sopenharmony_ci liftoff::SignExtendI32ToI64(this, dst); 4771cb0ef41Sopenharmony_ci break; 4781cb0ef41Sopenharmony_ci case LoadType::kI32Load: 4791cb0ef41Sopenharmony_ci mov(dst.gp(), src_op); 4801cb0ef41Sopenharmony_ci break; 4811cb0ef41Sopenharmony_ci case LoadType::kI64Load32U: 4821cb0ef41Sopenharmony_ci mov(dst.low_gp(), src_op); 4831cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); 4841cb0ef41Sopenharmony_ci break; 4851cb0ef41Sopenharmony_ci case LoadType::kI64Load32S: 4861cb0ef41Sopenharmony_ci mov(dst.low_gp(), src_op); 4871cb0ef41Sopenharmony_ci liftoff::SignExtendI32ToI64(this, dst); 4881cb0ef41Sopenharmony_ci break; 4891cb0ef41Sopenharmony_ci case LoadType::kI64Load: { 4901cb0ef41Sopenharmony_ci // Compute the operand for the load of the upper half. 4911cb0ef41Sopenharmony_ci Operand upper_src_op = 4921cb0ef41Sopenharmony_ci offset_reg == no_reg 4931cb0ef41Sopenharmony_ci ? Operand(src_addr, bit_cast<int32_t>(offset_imm + 4)) 4941cb0ef41Sopenharmony_ci : Operand(src_addr, offset_reg, times_1, offset_imm + 4); 4951cb0ef41Sopenharmony_ci // The high word has to be mov'ed first, such that this is the protected 4961cb0ef41Sopenharmony_ci // instruction. The mov of the low word cannot segfault. 4971cb0ef41Sopenharmony_ci mov(dst.high_gp(), upper_src_op); 4981cb0ef41Sopenharmony_ci mov(dst.low_gp(), src_op); 4991cb0ef41Sopenharmony_ci break; 5001cb0ef41Sopenharmony_ci } 5011cb0ef41Sopenharmony_ci case LoadType::kF32Load: 5021cb0ef41Sopenharmony_ci movss(dst.fp(), src_op); 5031cb0ef41Sopenharmony_ci break; 5041cb0ef41Sopenharmony_ci case LoadType::kF64Load: 5051cb0ef41Sopenharmony_ci movsd(dst.fp(), src_op); 5061cb0ef41Sopenharmony_ci break; 5071cb0ef41Sopenharmony_ci case LoadType::kS128Load: 5081cb0ef41Sopenharmony_ci movdqu(dst.fp(), src_op); 5091cb0ef41Sopenharmony_ci break; 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci} 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_civoid LiftoffAssembler::Store(Register dst_addr, Register offset_reg, 5141cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister src, 5151cb0ef41Sopenharmony_ci StoreType type, LiftoffRegList pinned, 5161cb0ef41Sopenharmony_ci uint32_t* protected_store_pc, bool is_store_mem) { 5171cb0ef41Sopenharmony_ci DCHECK_EQ(type.value_type() == kWasmI64, src.is_gp_pair()); 5181cb0ef41Sopenharmony_ci // Offsets >=2GB are statically OOB on 32-bit systems. 5191cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 5201cb0ef41Sopenharmony_ci Operand dst_op = offset_reg == no_reg 5211cb0ef41Sopenharmony_ci ? Operand(dst_addr, offset_imm) 5221cb0ef41Sopenharmony_ci : Operand(dst_addr, offset_reg, times_1, offset_imm); 5231cb0ef41Sopenharmony_ci if (protected_store_pc) *protected_store_pc = pc_offset(); 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ci switch (type.value()) { 5261cb0ef41Sopenharmony_ci case StoreType::kI64Store8: 5271cb0ef41Sopenharmony_ci src = src.low(); 5281cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 5291cb0ef41Sopenharmony_ci case StoreType::kI32Store8: 5301cb0ef41Sopenharmony_ci // Only the lower 4 registers can be addressed as 8-bit registers. 5311cb0ef41Sopenharmony_ci if (src.gp().is_byte_register()) { 5321cb0ef41Sopenharmony_ci mov_b(dst_op, src.gp()); 5331cb0ef41Sopenharmony_ci } else { 5341cb0ef41Sopenharmony_ci // We know that {src} is not a byte register, so the only pinned byte 5351cb0ef41Sopenharmony_ci // registers (beside the outer {pinned}) are {dst_addr} and potentially 5361cb0ef41Sopenharmony_ci // {offset_reg}. 5371cb0ef41Sopenharmony_ci LiftoffRegList pinned_byte = pinned | LiftoffRegList{dst_addr}; 5381cb0ef41Sopenharmony_ci if (offset_reg != no_reg) pinned_byte.set(offset_reg); 5391cb0ef41Sopenharmony_ci Register byte_src = 5401cb0ef41Sopenharmony_ci GetUnusedRegister(liftoff::kByteRegs.MaskOut(pinned_byte)).gp(); 5411cb0ef41Sopenharmony_ci mov(byte_src, src.gp()); 5421cb0ef41Sopenharmony_ci mov_b(dst_op, byte_src); 5431cb0ef41Sopenharmony_ci } 5441cb0ef41Sopenharmony_ci break; 5451cb0ef41Sopenharmony_ci case StoreType::kI64Store16: 5461cb0ef41Sopenharmony_ci src = src.low(); 5471cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 5481cb0ef41Sopenharmony_ci case StoreType::kI32Store16: 5491cb0ef41Sopenharmony_ci mov_w(dst_op, src.gp()); 5501cb0ef41Sopenharmony_ci break; 5511cb0ef41Sopenharmony_ci case StoreType::kI64Store32: 5521cb0ef41Sopenharmony_ci src = src.low(); 5531cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 5541cb0ef41Sopenharmony_ci case StoreType::kI32Store: 5551cb0ef41Sopenharmony_ci mov(dst_op, src.gp()); 5561cb0ef41Sopenharmony_ci break; 5571cb0ef41Sopenharmony_ci case StoreType::kI64Store: { 5581cb0ef41Sopenharmony_ci // Compute the operand for the store of the upper half. 5591cb0ef41Sopenharmony_ci Operand upper_dst_op = 5601cb0ef41Sopenharmony_ci offset_reg == no_reg 5611cb0ef41Sopenharmony_ci ? Operand(dst_addr, bit_cast<int32_t>(offset_imm + 4)) 5621cb0ef41Sopenharmony_ci : Operand(dst_addr, offset_reg, times_1, offset_imm + 4); 5631cb0ef41Sopenharmony_ci // The high word has to be mov'ed first, such that this is the protected 5641cb0ef41Sopenharmony_ci // instruction. The mov of the low word cannot segfault. 5651cb0ef41Sopenharmony_ci mov(upper_dst_op, src.high_gp()); 5661cb0ef41Sopenharmony_ci mov(dst_op, src.low_gp()); 5671cb0ef41Sopenharmony_ci break; 5681cb0ef41Sopenharmony_ci } 5691cb0ef41Sopenharmony_ci case StoreType::kF32Store: 5701cb0ef41Sopenharmony_ci movss(dst_op, src.fp()); 5711cb0ef41Sopenharmony_ci break; 5721cb0ef41Sopenharmony_ci case StoreType::kF64Store: 5731cb0ef41Sopenharmony_ci movsd(dst_op, src.fp()); 5741cb0ef41Sopenharmony_ci break; 5751cb0ef41Sopenharmony_ci case StoreType::kS128Store: 5761cb0ef41Sopenharmony_ci Movdqu(dst_op, src.fp()); 5771cb0ef41Sopenharmony_ci break; 5781cb0ef41Sopenharmony_ci } 5791cb0ef41Sopenharmony_ci} 5801cb0ef41Sopenharmony_ci 5811cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicLoad(LiftoffRegister dst, Register src_addr, 5821cb0ef41Sopenharmony_ci Register offset_reg, uint32_t offset_imm, 5831cb0ef41Sopenharmony_ci LoadType type, LiftoffRegList pinned) { 5841cb0ef41Sopenharmony_ci if (type.value() != LoadType::kI64Load) { 5851cb0ef41Sopenharmony_ci Load(dst, src_addr, offset_reg, offset_imm, type, pinned, nullptr, true); 5861cb0ef41Sopenharmony_ci return; 5871cb0ef41Sopenharmony_ci } 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci DCHECK_EQ(type.value_type() == kWasmI64, dst.is_gp_pair()); 5901cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 5911cb0ef41Sopenharmony_ci Operand src_op = offset_reg == no_reg 5921cb0ef41Sopenharmony_ci ? Operand(src_addr, offset_imm) 5931cb0ef41Sopenharmony_ci : Operand(src_addr, offset_reg, times_1, offset_imm); 5941cb0ef41Sopenharmony_ci 5951cb0ef41Sopenharmony_ci movsd(liftoff::kScratchDoubleReg, src_op); 5961cb0ef41Sopenharmony_ci Pextrd(dst.low().gp(), liftoff::kScratchDoubleReg, 0); 5971cb0ef41Sopenharmony_ci Pextrd(dst.high().gp(), liftoff::kScratchDoubleReg, 1); 5981cb0ef41Sopenharmony_ci} 5991cb0ef41Sopenharmony_ci 6001cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicStore(Register dst_addr, Register offset_reg, 6011cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister src, 6021cb0ef41Sopenharmony_ci StoreType type, LiftoffRegList pinned) { 6031cb0ef41Sopenharmony_ci DCHECK_NE(offset_reg, no_reg); 6041cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 6051cb0ef41Sopenharmony_ci Operand dst_op = Operand(dst_addr, offset_reg, times_1, offset_imm); 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_ci // i64 store uses a totally different approach, hence implement it separately. 6081cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 6091cb0ef41Sopenharmony_ci auto scratch2 = GetUnusedRegister(kFpReg, pinned).fp(); 6101cb0ef41Sopenharmony_ci movd(liftoff::kScratchDoubleReg, src.low().gp()); 6111cb0ef41Sopenharmony_ci movd(scratch2, src.high().gp()); 6121cb0ef41Sopenharmony_ci Punpckldq(liftoff::kScratchDoubleReg, scratch2); 6131cb0ef41Sopenharmony_ci movsd(dst_op, liftoff::kScratchDoubleReg); 6141cb0ef41Sopenharmony_ci // This lock+or is needed to achieve sequential consistency. 6151cb0ef41Sopenharmony_ci lock(); 6161cb0ef41Sopenharmony_ci or_(Operand(esp, 0), Immediate(0)); 6171cb0ef41Sopenharmony_ci return; 6181cb0ef41Sopenharmony_ci } 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ci // Other i64 stores actually only use the low word. 6211cb0ef41Sopenharmony_ci if (src.is_pair()) src = src.low(); 6221cb0ef41Sopenharmony_ci Register src_gp = src.gp(); 6231cb0ef41Sopenharmony_ci 6241cb0ef41Sopenharmony_ci bool is_byte_store = type.size() == 1; 6251cb0ef41Sopenharmony_ci LiftoffRegList src_candidates = 6261cb0ef41Sopenharmony_ci is_byte_store ? liftoff::kByteRegs : kGpCacheRegList; 6271cb0ef41Sopenharmony_ci pinned = pinned | LiftoffRegList{dst_addr, src, offset_reg}; 6281cb0ef41Sopenharmony_ci 6291cb0ef41Sopenharmony_ci // Ensure that {src} is a valid and otherwise unused register. 6301cb0ef41Sopenharmony_ci if (!src_candidates.has(src) || cache_state_.is_used(src)) { 6311cb0ef41Sopenharmony_ci // If there are no unused candidate registers, but {src} is a candidate, 6321cb0ef41Sopenharmony_ci // then spill other uses of {src}. Otherwise spill any candidate register 6331cb0ef41Sopenharmony_ci // and use that. 6341cb0ef41Sopenharmony_ci LiftoffRegList unpinned_candidates = src_candidates.MaskOut(pinned); 6351cb0ef41Sopenharmony_ci if (!cache_state_.has_unused_register(unpinned_candidates) && 6361cb0ef41Sopenharmony_ci src_candidates.has(src)) { 6371cb0ef41Sopenharmony_ci SpillRegister(src); 6381cb0ef41Sopenharmony_ci } else { 6391cb0ef41Sopenharmony_ci Register safe_src = GetUnusedRegister(unpinned_candidates).gp(); 6401cb0ef41Sopenharmony_ci mov(safe_src, src_gp); 6411cb0ef41Sopenharmony_ci src_gp = safe_src; 6421cb0ef41Sopenharmony_ci } 6431cb0ef41Sopenharmony_ci } 6441cb0ef41Sopenharmony_ci 6451cb0ef41Sopenharmony_ci switch (type.value()) { 6461cb0ef41Sopenharmony_ci case StoreType::kI64Store8: 6471cb0ef41Sopenharmony_ci case StoreType::kI32Store8: 6481cb0ef41Sopenharmony_ci xchg_b(src_gp, dst_op); 6491cb0ef41Sopenharmony_ci return; 6501cb0ef41Sopenharmony_ci case StoreType::kI64Store16: 6511cb0ef41Sopenharmony_ci case StoreType::kI32Store16: 6521cb0ef41Sopenharmony_ci xchg_w(src_gp, dst_op); 6531cb0ef41Sopenharmony_ci return; 6541cb0ef41Sopenharmony_ci case StoreType::kI64Store32: 6551cb0ef41Sopenharmony_ci case StoreType::kI32Store: 6561cb0ef41Sopenharmony_ci xchg(src_gp, dst_op); 6571cb0ef41Sopenharmony_ci return; 6581cb0ef41Sopenharmony_ci default: 6591cb0ef41Sopenharmony_ci UNREACHABLE(); 6601cb0ef41Sopenharmony_ci } 6611cb0ef41Sopenharmony_ci} 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_cinamespace liftoff { 6641cb0ef41Sopenharmony_ci#define __ lasm-> 6651cb0ef41Sopenharmony_ci 6661cb0ef41Sopenharmony_cienum Binop { kAdd, kSub, kAnd, kOr, kXor, kExchange }; 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_ciinline void AtomicAddOrSubOrExchange32(LiftoffAssembler* lasm, Binop binop, 6691cb0ef41Sopenharmony_ci Register dst_addr, Register offset_reg, 6701cb0ef41Sopenharmony_ci uint32_t offset_imm, 6711cb0ef41Sopenharmony_ci LiftoffRegister value, 6721cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 6731cb0ef41Sopenharmony_ci DCHECK_EQ(value, result); 6741cb0ef41Sopenharmony_ci DCHECK(!__ cache_state()->is_used(result)); 6751cb0ef41Sopenharmony_ci bool is_64_bit_op = type.value_type() == kWasmI64; 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ci Register value_reg = is_64_bit_op ? value.low_gp() : value.gp(); 6781cb0ef41Sopenharmony_ci Register result_reg = is_64_bit_op ? result.low_gp() : result.gp(); 6791cb0ef41Sopenharmony_ci 6801cb0ef41Sopenharmony_ci bool is_byte_store = type.size() == 1; 6811cb0ef41Sopenharmony_ci LiftoffRegList pinned = {dst_addr, value_reg, offset_reg}; 6821cb0ef41Sopenharmony_ci 6831cb0ef41Sopenharmony_ci // Ensure that {value_reg} is a valid register. 6841cb0ef41Sopenharmony_ci if (is_byte_store && !liftoff::kByteRegs.has(value_reg)) { 6851cb0ef41Sopenharmony_ci Register safe_value_reg = 6861cb0ef41Sopenharmony_ci __ GetUnusedRegister(liftoff::kByteRegs.MaskOut(pinned)).gp(); 6871cb0ef41Sopenharmony_ci __ mov(safe_value_reg, value_reg); 6881cb0ef41Sopenharmony_ci value_reg = safe_value_reg; 6891cb0ef41Sopenharmony_ci } 6901cb0ef41Sopenharmony_ci 6911cb0ef41Sopenharmony_ci Operand dst_op = Operand(dst_addr, offset_reg, times_1, offset_imm); 6921cb0ef41Sopenharmony_ci if (binop == kSub) { 6931cb0ef41Sopenharmony_ci __ neg(value_reg); 6941cb0ef41Sopenharmony_ci } 6951cb0ef41Sopenharmony_ci if (binop != kExchange) { 6961cb0ef41Sopenharmony_ci __ lock(); 6971cb0ef41Sopenharmony_ci } 6981cb0ef41Sopenharmony_ci switch (type.value()) { 6991cb0ef41Sopenharmony_ci case StoreType::kI64Store8: 7001cb0ef41Sopenharmony_ci case StoreType::kI32Store8: 7011cb0ef41Sopenharmony_ci if (binop == kExchange) { 7021cb0ef41Sopenharmony_ci __ xchg_b(value_reg, dst_op); 7031cb0ef41Sopenharmony_ci } else { 7041cb0ef41Sopenharmony_ci __ xadd_b(dst_op, value_reg); 7051cb0ef41Sopenharmony_ci } 7061cb0ef41Sopenharmony_ci __ movzx_b(result_reg, value_reg); 7071cb0ef41Sopenharmony_ci break; 7081cb0ef41Sopenharmony_ci case StoreType::kI64Store16: 7091cb0ef41Sopenharmony_ci case StoreType::kI32Store16: 7101cb0ef41Sopenharmony_ci if (binop == kExchange) { 7111cb0ef41Sopenharmony_ci __ xchg_w(value_reg, dst_op); 7121cb0ef41Sopenharmony_ci } else { 7131cb0ef41Sopenharmony_ci __ xadd_w(dst_op, value_reg); 7141cb0ef41Sopenharmony_ci } 7151cb0ef41Sopenharmony_ci __ movzx_w(result_reg, value_reg); 7161cb0ef41Sopenharmony_ci break; 7171cb0ef41Sopenharmony_ci case StoreType::kI64Store32: 7181cb0ef41Sopenharmony_ci case StoreType::kI32Store: 7191cb0ef41Sopenharmony_ci if (binop == kExchange) { 7201cb0ef41Sopenharmony_ci __ xchg(value_reg, dst_op); 7211cb0ef41Sopenharmony_ci } else { 7221cb0ef41Sopenharmony_ci __ xadd(dst_op, value_reg); 7231cb0ef41Sopenharmony_ci } 7241cb0ef41Sopenharmony_ci if (value_reg != result_reg) { 7251cb0ef41Sopenharmony_ci __ mov(result_reg, value_reg); 7261cb0ef41Sopenharmony_ci } 7271cb0ef41Sopenharmony_ci break; 7281cb0ef41Sopenharmony_ci default: 7291cb0ef41Sopenharmony_ci UNREACHABLE(); 7301cb0ef41Sopenharmony_ci } 7311cb0ef41Sopenharmony_ci if (is_64_bit_op) { 7321cb0ef41Sopenharmony_ci __ xor_(result.high_gp(), result.high_gp()); 7331cb0ef41Sopenharmony_ci } 7341cb0ef41Sopenharmony_ci} 7351cb0ef41Sopenharmony_ci 7361cb0ef41Sopenharmony_ciinline void AtomicBinop32(LiftoffAssembler* lasm, Binop op, Register dst_addr, 7371cb0ef41Sopenharmony_ci Register offset_reg, uint32_t offset_imm, 7381cb0ef41Sopenharmony_ci LiftoffRegister value, LiftoffRegister result, 7391cb0ef41Sopenharmony_ci StoreType type) { 7401cb0ef41Sopenharmony_ci DCHECK_EQ(value, result); 7411cb0ef41Sopenharmony_ci DCHECK(!__ cache_state()->is_used(result)); 7421cb0ef41Sopenharmony_ci bool is_64_bit_op = type.value_type() == kWasmI64; 7431cb0ef41Sopenharmony_ci 7441cb0ef41Sopenharmony_ci Register value_reg = is_64_bit_op ? value.low_gp() : value.gp(); 7451cb0ef41Sopenharmony_ci Register result_reg = is_64_bit_op ? result.low_gp() : result.gp(); 7461cb0ef41Sopenharmony_ci 7471cb0ef41Sopenharmony_ci // The cmpxchg instruction uses eax to store the old value of the 7481cb0ef41Sopenharmony_ci // compare-exchange primitive. Therefore we have to spill the register and 7491cb0ef41Sopenharmony_ci // move any use to another register. 7501cb0ef41Sopenharmony_ci __ ClearRegister(eax, {&dst_addr, &offset_reg, &value_reg}, 7511cb0ef41Sopenharmony_ci LiftoffRegList{dst_addr, offset_reg, value_reg}); 7521cb0ef41Sopenharmony_ci 7531cb0ef41Sopenharmony_ci bool is_byte_store = type.size() == 1; 7541cb0ef41Sopenharmony_ci Register scratch = no_reg; 7551cb0ef41Sopenharmony_ci if (is_byte_store) { 7561cb0ef41Sopenharmony_ci // The scratch register has to be a byte register. As we are already tight 7571cb0ef41Sopenharmony_ci // on registers, we just use the root register here. 7581cb0ef41Sopenharmony_ci static_assert(!kLiftoffAssemblerGpCacheRegs.has(kRootRegister), 7591cb0ef41Sopenharmony_ci "root register is not Liftoff cache register"); 7601cb0ef41Sopenharmony_ci DCHECK(kRootRegister.is_byte_register()); 7611cb0ef41Sopenharmony_ci __ push(kRootRegister); 7621cb0ef41Sopenharmony_ci scratch = kRootRegister; 7631cb0ef41Sopenharmony_ci } else { 7641cb0ef41Sopenharmony_ci scratch = __ GetUnusedRegister( 7651cb0ef41Sopenharmony_ci kGpReg, LiftoffRegList{dst_addr, offset_reg, value_reg, eax}) 7661cb0ef41Sopenharmony_ci .gp(); 7671cb0ef41Sopenharmony_ci } 7681cb0ef41Sopenharmony_ci 7691cb0ef41Sopenharmony_ci Operand dst_op = Operand(dst_addr, offset_reg, times_1, offset_imm); 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_ci switch (type.value()) { 7721cb0ef41Sopenharmony_ci case StoreType::kI32Store8: 7731cb0ef41Sopenharmony_ci case StoreType::kI64Store8: { 7741cb0ef41Sopenharmony_ci __ xor_(eax, eax); 7751cb0ef41Sopenharmony_ci __ mov_b(eax, dst_op); 7761cb0ef41Sopenharmony_ci break; 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci case StoreType::kI32Store16: 7791cb0ef41Sopenharmony_ci case StoreType::kI64Store16: { 7801cb0ef41Sopenharmony_ci __ xor_(eax, eax); 7811cb0ef41Sopenharmony_ci __ mov_w(eax, dst_op); 7821cb0ef41Sopenharmony_ci break; 7831cb0ef41Sopenharmony_ci } 7841cb0ef41Sopenharmony_ci case StoreType::kI32Store: 7851cb0ef41Sopenharmony_ci case StoreType::kI64Store32: { 7861cb0ef41Sopenharmony_ci __ mov(eax, dst_op); 7871cb0ef41Sopenharmony_ci break; 7881cb0ef41Sopenharmony_ci } 7891cb0ef41Sopenharmony_ci default: 7901cb0ef41Sopenharmony_ci UNREACHABLE(); 7911cb0ef41Sopenharmony_ci } 7921cb0ef41Sopenharmony_ci 7931cb0ef41Sopenharmony_ci Label binop; 7941cb0ef41Sopenharmony_ci __ bind(&binop); 7951cb0ef41Sopenharmony_ci __ mov(scratch, eax); 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_ci switch (op) { 7981cb0ef41Sopenharmony_ci case kAnd: { 7991cb0ef41Sopenharmony_ci __ and_(scratch, value_reg); 8001cb0ef41Sopenharmony_ci break; 8011cb0ef41Sopenharmony_ci } 8021cb0ef41Sopenharmony_ci case kOr: { 8031cb0ef41Sopenharmony_ci __ or_(scratch, value_reg); 8041cb0ef41Sopenharmony_ci break; 8051cb0ef41Sopenharmony_ci } 8061cb0ef41Sopenharmony_ci case kXor: { 8071cb0ef41Sopenharmony_ci __ xor_(scratch, value_reg); 8081cb0ef41Sopenharmony_ci break; 8091cb0ef41Sopenharmony_ci } 8101cb0ef41Sopenharmony_ci default: 8111cb0ef41Sopenharmony_ci UNREACHABLE(); 8121cb0ef41Sopenharmony_ci } 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci __ lock(); 8151cb0ef41Sopenharmony_ci 8161cb0ef41Sopenharmony_ci switch (type.value()) { 8171cb0ef41Sopenharmony_ci case StoreType::kI32Store8: 8181cb0ef41Sopenharmony_ci case StoreType::kI64Store8: { 8191cb0ef41Sopenharmony_ci __ cmpxchg_b(dst_op, scratch); 8201cb0ef41Sopenharmony_ci break; 8211cb0ef41Sopenharmony_ci } 8221cb0ef41Sopenharmony_ci case StoreType::kI32Store16: 8231cb0ef41Sopenharmony_ci case StoreType::kI64Store16: { 8241cb0ef41Sopenharmony_ci __ cmpxchg_w(dst_op, scratch); 8251cb0ef41Sopenharmony_ci break; 8261cb0ef41Sopenharmony_ci } 8271cb0ef41Sopenharmony_ci case StoreType::kI32Store: 8281cb0ef41Sopenharmony_ci case StoreType::kI64Store32: { 8291cb0ef41Sopenharmony_ci __ cmpxchg(dst_op, scratch); 8301cb0ef41Sopenharmony_ci break; 8311cb0ef41Sopenharmony_ci } 8321cb0ef41Sopenharmony_ci default: 8331cb0ef41Sopenharmony_ci UNREACHABLE(); 8341cb0ef41Sopenharmony_ci } 8351cb0ef41Sopenharmony_ci __ j(not_equal, &binop); 8361cb0ef41Sopenharmony_ci 8371cb0ef41Sopenharmony_ci if (is_byte_store) { 8381cb0ef41Sopenharmony_ci __ pop(kRootRegister); 8391cb0ef41Sopenharmony_ci } 8401cb0ef41Sopenharmony_ci if (result_reg != eax) { 8411cb0ef41Sopenharmony_ci __ mov(result_reg, eax); 8421cb0ef41Sopenharmony_ci } 8431cb0ef41Sopenharmony_ci if (is_64_bit_op) { 8441cb0ef41Sopenharmony_ci __ xor_(result.high_gp(), result.high_gp()); 8451cb0ef41Sopenharmony_ci } 8461cb0ef41Sopenharmony_ci} 8471cb0ef41Sopenharmony_ci 8481cb0ef41Sopenharmony_ciinline void AtomicBinop64(LiftoffAssembler* lasm, Binop op, Register dst_addr, 8491cb0ef41Sopenharmony_ci Register offset_reg, uint32_t offset_imm, 8501cb0ef41Sopenharmony_ci LiftoffRegister value, LiftoffRegister result) { 8511cb0ef41Sopenharmony_ci // We need {ebx} here, which is the root register. As the root register it 8521cb0ef41Sopenharmony_ci // needs special treatment. As we use {ebx} directly in the code below, we 8531cb0ef41Sopenharmony_ci // have to make sure here that the root register is actually {ebx}. 8541cb0ef41Sopenharmony_ci static_assert(kRootRegister == ebx, 8551cb0ef41Sopenharmony_ci "The following code assumes that kRootRegister == ebx"); 8561cb0ef41Sopenharmony_ci __ push(ebx); 8571cb0ef41Sopenharmony_ci 8581cb0ef41Sopenharmony_ci // Store the value on the stack, so that we can use it for retries. 8591cb0ef41Sopenharmony_ci __ AllocateStackSpace(8); 8601cb0ef41Sopenharmony_ci Operand value_op_hi = Operand(esp, 0); 8611cb0ef41Sopenharmony_ci Operand value_op_lo = Operand(esp, 4); 8621cb0ef41Sopenharmony_ci __ mov(value_op_lo, value.low_gp()); 8631cb0ef41Sopenharmony_ci __ mov(value_op_hi, value.high_gp()); 8641cb0ef41Sopenharmony_ci 8651cb0ef41Sopenharmony_ci // We want to use the compare-exchange instruction here. It uses registers 8661cb0ef41Sopenharmony_ci // as follows: old-value = EDX:EAX; new-value = ECX:EBX. 8671cb0ef41Sopenharmony_ci Register old_hi = edx; 8681cb0ef41Sopenharmony_ci Register old_lo = eax; 8691cb0ef41Sopenharmony_ci Register new_hi = ecx; 8701cb0ef41Sopenharmony_ci Register new_lo = ebx; 8711cb0ef41Sopenharmony_ci // Base and offset need separate registers that do not alias with the 8721cb0ef41Sopenharmony_ci // ones above. 8731cb0ef41Sopenharmony_ci Register base = esi; 8741cb0ef41Sopenharmony_ci Register offset = edi; 8751cb0ef41Sopenharmony_ci 8761cb0ef41Sopenharmony_ci // Swap base and offset register if necessary to avoid unnecessary 8771cb0ef41Sopenharmony_ci // moves. 8781cb0ef41Sopenharmony_ci if (dst_addr == offset || offset_reg == base) { 8791cb0ef41Sopenharmony_ci std::swap(dst_addr, offset_reg); 8801cb0ef41Sopenharmony_ci } 8811cb0ef41Sopenharmony_ci // Spill all these registers if they are still holding other values. 8821cb0ef41Sopenharmony_ci __ SpillRegisters(old_hi, old_lo, new_hi, base, offset); 8831cb0ef41Sopenharmony_ci __ ParallelRegisterMove( 8841cb0ef41Sopenharmony_ci {{LiftoffRegister::ForPair(base, offset), 8851cb0ef41Sopenharmony_ci LiftoffRegister::ForPair(dst_addr, offset_reg), kI64}}); 8861cb0ef41Sopenharmony_ci 8871cb0ef41Sopenharmony_ci Operand dst_op_lo = Operand(base, offset, times_1, offset_imm); 8881cb0ef41Sopenharmony_ci Operand dst_op_hi = Operand(base, offset, times_1, offset_imm + 4); 8891cb0ef41Sopenharmony_ci 8901cb0ef41Sopenharmony_ci // Load the old value from memory. 8911cb0ef41Sopenharmony_ci __ mov(old_lo, dst_op_lo); 8921cb0ef41Sopenharmony_ci __ mov(old_hi, dst_op_hi); 8931cb0ef41Sopenharmony_ci Label retry; 8941cb0ef41Sopenharmony_ci __ bind(&retry); 8951cb0ef41Sopenharmony_ci __ mov(new_lo, old_lo); 8961cb0ef41Sopenharmony_ci __ mov(new_hi, old_hi); 8971cb0ef41Sopenharmony_ci switch (op) { 8981cb0ef41Sopenharmony_ci case kAdd: 8991cb0ef41Sopenharmony_ci __ add(new_lo, value_op_lo); 9001cb0ef41Sopenharmony_ci __ adc(new_hi, value_op_hi); 9011cb0ef41Sopenharmony_ci break; 9021cb0ef41Sopenharmony_ci case kSub: 9031cb0ef41Sopenharmony_ci __ sub(new_lo, value_op_lo); 9041cb0ef41Sopenharmony_ci __ sbb(new_hi, value_op_hi); 9051cb0ef41Sopenharmony_ci break; 9061cb0ef41Sopenharmony_ci case kAnd: 9071cb0ef41Sopenharmony_ci __ and_(new_lo, value_op_lo); 9081cb0ef41Sopenharmony_ci __ and_(new_hi, value_op_hi); 9091cb0ef41Sopenharmony_ci break; 9101cb0ef41Sopenharmony_ci case kOr: 9111cb0ef41Sopenharmony_ci __ or_(new_lo, value_op_lo); 9121cb0ef41Sopenharmony_ci __ or_(new_hi, value_op_hi); 9131cb0ef41Sopenharmony_ci break; 9141cb0ef41Sopenharmony_ci case kXor: 9151cb0ef41Sopenharmony_ci __ xor_(new_lo, value_op_lo); 9161cb0ef41Sopenharmony_ci __ xor_(new_hi, value_op_hi); 9171cb0ef41Sopenharmony_ci break; 9181cb0ef41Sopenharmony_ci case kExchange: 9191cb0ef41Sopenharmony_ci __ mov(new_lo, value_op_lo); 9201cb0ef41Sopenharmony_ci __ mov(new_hi, value_op_hi); 9211cb0ef41Sopenharmony_ci break; 9221cb0ef41Sopenharmony_ci } 9231cb0ef41Sopenharmony_ci __ lock(); 9241cb0ef41Sopenharmony_ci __ cmpxchg8b(dst_op_lo); 9251cb0ef41Sopenharmony_ci __ j(not_equal, &retry); 9261cb0ef41Sopenharmony_ci 9271cb0ef41Sopenharmony_ci // Deallocate the stack space again. 9281cb0ef41Sopenharmony_ci __ add(esp, Immediate(8)); 9291cb0ef41Sopenharmony_ci // Restore the root register, and we are done. 9301cb0ef41Sopenharmony_ci __ pop(kRootRegister); 9311cb0ef41Sopenharmony_ci 9321cb0ef41Sopenharmony_ci // Move the result into the correct registers. 9331cb0ef41Sopenharmony_ci __ ParallelRegisterMove( 9341cb0ef41Sopenharmony_ci {{result, LiftoffRegister::ForPair(old_lo, old_hi), kI64}}); 9351cb0ef41Sopenharmony_ci} 9361cb0ef41Sopenharmony_ci 9371cb0ef41Sopenharmony_ci#undef __ 9381cb0ef41Sopenharmony_ci} // namespace liftoff 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicAdd(Register dst_addr, Register offset_reg, 9411cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister value, 9421cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 9431cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 9441cb0ef41Sopenharmony_ci liftoff::AtomicBinop64(this, liftoff::kAdd, dst_addr, offset_reg, 9451cb0ef41Sopenharmony_ci offset_imm, value, result); 9461cb0ef41Sopenharmony_ci return; 9471cb0ef41Sopenharmony_ci } 9481cb0ef41Sopenharmony_ci 9491cb0ef41Sopenharmony_ci liftoff::AtomicAddOrSubOrExchange32(this, liftoff::kAdd, dst_addr, offset_reg, 9501cb0ef41Sopenharmony_ci offset_imm, value, result, type); 9511cb0ef41Sopenharmony_ci} 9521cb0ef41Sopenharmony_ci 9531cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicSub(Register dst_addr, Register offset_reg, 9541cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister value, 9551cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 9561cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 9571cb0ef41Sopenharmony_ci liftoff::AtomicBinop64(this, liftoff::kSub, dst_addr, offset_reg, 9581cb0ef41Sopenharmony_ci offset_imm, value, result); 9591cb0ef41Sopenharmony_ci return; 9601cb0ef41Sopenharmony_ci } 9611cb0ef41Sopenharmony_ci liftoff::AtomicAddOrSubOrExchange32(this, liftoff::kSub, dst_addr, offset_reg, 9621cb0ef41Sopenharmony_ci offset_imm, value, result, type); 9631cb0ef41Sopenharmony_ci} 9641cb0ef41Sopenharmony_ci 9651cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicAnd(Register dst_addr, Register offset_reg, 9661cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister value, 9671cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 9681cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 9691cb0ef41Sopenharmony_ci liftoff::AtomicBinop64(this, liftoff::kAnd, dst_addr, offset_reg, 9701cb0ef41Sopenharmony_ci offset_imm, value, result); 9711cb0ef41Sopenharmony_ci return; 9721cb0ef41Sopenharmony_ci } 9731cb0ef41Sopenharmony_ci 9741cb0ef41Sopenharmony_ci liftoff::AtomicBinop32(this, liftoff::kAnd, dst_addr, offset_reg, offset_imm, 9751cb0ef41Sopenharmony_ci value, result, type); 9761cb0ef41Sopenharmony_ci} 9771cb0ef41Sopenharmony_ci 9781cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicOr(Register dst_addr, Register offset_reg, 9791cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister value, 9801cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 9811cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 9821cb0ef41Sopenharmony_ci liftoff::AtomicBinop64(this, liftoff::kOr, dst_addr, offset_reg, offset_imm, 9831cb0ef41Sopenharmony_ci value, result); 9841cb0ef41Sopenharmony_ci return; 9851cb0ef41Sopenharmony_ci } 9861cb0ef41Sopenharmony_ci 9871cb0ef41Sopenharmony_ci liftoff::AtomicBinop32(this, liftoff::kOr, dst_addr, offset_reg, offset_imm, 9881cb0ef41Sopenharmony_ci value, result, type); 9891cb0ef41Sopenharmony_ci} 9901cb0ef41Sopenharmony_ci 9911cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicXor(Register dst_addr, Register offset_reg, 9921cb0ef41Sopenharmony_ci uint32_t offset_imm, LiftoffRegister value, 9931cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 9941cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 9951cb0ef41Sopenharmony_ci liftoff::AtomicBinop64(this, liftoff::kXor, dst_addr, offset_reg, 9961cb0ef41Sopenharmony_ci offset_imm, value, result); 9971cb0ef41Sopenharmony_ci return; 9981cb0ef41Sopenharmony_ci } 9991cb0ef41Sopenharmony_ci 10001cb0ef41Sopenharmony_ci liftoff::AtomicBinop32(this, liftoff::kXor, dst_addr, offset_reg, offset_imm, 10011cb0ef41Sopenharmony_ci value, result, type); 10021cb0ef41Sopenharmony_ci} 10031cb0ef41Sopenharmony_ci 10041cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicExchange(Register dst_addr, Register offset_reg, 10051cb0ef41Sopenharmony_ci uint32_t offset_imm, 10061cb0ef41Sopenharmony_ci LiftoffRegister value, 10071cb0ef41Sopenharmony_ci LiftoffRegister result, StoreType type) { 10081cb0ef41Sopenharmony_ci if (type.value() == StoreType::kI64Store) { 10091cb0ef41Sopenharmony_ci liftoff::AtomicBinop64(this, liftoff::kExchange, dst_addr, offset_reg, 10101cb0ef41Sopenharmony_ci offset_imm, value, result); 10111cb0ef41Sopenharmony_ci return; 10121cb0ef41Sopenharmony_ci } 10131cb0ef41Sopenharmony_ci liftoff::AtomicAddOrSubOrExchange32(this, liftoff::kExchange, dst_addr, 10141cb0ef41Sopenharmony_ci offset_reg, offset_imm, value, result, 10151cb0ef41Sopenharmony_ci type); 10161cb0ef41Sopenharmony_ci} 10171cb0ef41Sopenharmony_ci 10181cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicCompareExchange( 10191cb0ef41Sopenharmony_ci Register dst_addr, Register offset_reg, uint32_t offset_imm, 10201cb0ef41Sopenharmony_ci LiftoffRegister expected, LiftoffRegister new_value, LiftoffRegister result, 10211cb0ef41Sopenharmony_ci StoreType type) { 10221cb0ef41Sopenharmony_ci // We expect that the offset has already been added to {dst_addr}, and no 10231cb0ef41Sopenharmony_ci // {offset_reg} is provided. This is to save registers. 10241cb0ef41Sopenharmony_ci DCHECK_EQ(offset_reg, no_reg); 10251cb0ef41Sopenharmony_ci 10261cb0ef41Sopenharmony_ci DCHECK_EQ(result, expected); 10271cb0ef41Sopenharmony_ci 10281cb0ef41Sopenharmony_ci if (type.value() != StoreType::kI64Store) { 10291cb0ef41Sopenharmony_ci bool is_64_bit_op = type.value_type() == kWasmI64; 10301cb0ef41Sopenharmony_ci 10311cb0ef41Sopenharmony_ci Register value_reg = is_64_bit_op ? new_value.low_gp() : new_value.gp(); 10321cb0ef41Sopenharmony_ci Register expected_reg = is_64_bit_op ? expected.low_gp() : expected.gp(); 10331cb0ef41Sopenharmony_ci Register result_reg = expected_reg; 10341cb0ef41Sopenharmony_ci 10351cb0ef41Sopenharmony_ci // The cmpxchg instruction uses eax to store the old value of the 10361cb0ef41Sopenharmony_ci // compare-exchange primitive. Therefore we have to spill the register and 10371cb0ef41Sopenharmony_ci // move any use to another register. 10381cb0ef41Sopenharmony_ci ClearRegister(eax, {&dst_addr, &value_reg}, 10391cb0ef41Sopenharmony_ci LiftoffRegList{dst_addr, value_reg, expected_reg}); 10401cb0ef41Sopenharmony_ci if (expected_reg != eax) { 10411cb0ef41Sopenharmony_ci mov(eax, expected_reg); 10421cb0ef41Sopenharmony_ci expected_reg = eax; 10431cb0ef41Sopenharmony_ci } 10441cb0ef41Sopenharmony_ci 10451cb0ef41Sopenharmony_ci bool is_byte_store = type.size() == 1; 10461cb0ef41Sopenharmony_ci LiftoffRegList pinned = {dst_addr, value_reg, expected_reg}; 10471cb0ef41Sopenharmony_ci 10481cb0ef41Sopenharmony_ci // Ensure that {value_reg} is a valid register. 10491cb0ef41Sopenharmony_ci if (is_byte_store && !liftoff::kByteRegs.has(value_reg)) { 10501cb0ef41Sopenharmony_ci Register safe_value_reg = 10511cb0ef41Sopenharmony_ci pinned.set(GetUnusedRegister(liftoff::kByteRegs.MaskOut(pinned))) 10521cb0ef41Sopenharmony_ci .gp(); 10531cb0ef41Sopenharmony_ci mov(safe_value_reg, value_reg); 10541cb0ef41Sopenharmony_ci value_reg = safe_value_reg; 10551cb0ef41Sopenharmony_ci pinned.clear(LiftoffRegister(value_reg)); 10561cb0ef41Sopenharmony_ci } 10571cb0ef41Sopenharmony_ci 10581cb0ef41Sopenharmony_ci 10591cb0ef41Sopenharmony_ci Operand dst_op = Operand(dst_addr, offset_imm); 10601cb0ef41Sopenharmony_ci 10611cb0ef41Sopenharmony_ci lock(); 10621cb0ef41Sopenharmony_ci switch (type.value()) { 10631cb0ef41Sopenharmony_ci case StoreType::kI32Store8: 10641cb0ef41Sopenharmony_ci case StoreType::kI64Store8: { 10651cb0ef41Sopenharmony_ci cmpxchg_b(dst_op, value_reg); 10661cb0ef41Sopenharmony_ci movzx_b(result_reg, eax); 10671cb0ef41Sopenharmony_ci break; 10681cb0ef41Sopenharmony_ci } 10691cb0ef41Sopenharmony_ci case StoreType::kI32Store16: 10701cb0ef41Sopenharmony_ci case StoreType::kI64Store16: { 10711cb0ef41Sopenharmony_ci cmpxchg_w(dst_op, value_reg); 10721cb0ef41Sopenharmony_ci movzx_w(result_reg, eax); 10731cb0ef41Sopenharmony_ci break; 10741cb0ef41Sopenharmony_ci } 10751cb0ef41Sopenharmony_ci case StoreType::kI32Store: 10761cb0ef41Sopenharmony_ci case StoreType::kI64Store32: { 10771cb0ef41Sopenharmony_ci cmpxchg(dst_op, value_reg); 10781cb0ef41Sopenharmony_ci if (result_reg != eax) { 10791cb0ef41Sopenharmony_ci mov(result_reg, eax); 10801cb0ef41Sopenharmony_ci } 10811cb0ef41Sopenharmony_ci break; 10821cb0ef41Sopenharmony_ci } 10831cb0ef41Sopenharmony_ci default: 10841cb0ef41Sopenharmony_ci UNREACHABLE(); 10851cb0ef41Sopenharmony_ci } 10861cb0ef41Sopenharmony_ci if (is_64_bit_op) { 10871cb0ef41Sopenharmony_ci xor_(result.high_gp(), result.high_gp()); 10881cb0ef41Sopenharmony_ci } 10891cb0ef41Sopenharmony_ci return; 10901cb0ef41Sopenharmony_ci } 10911cb0ef41Sopenharmony_ci 10921cb0ef41Sopenharmony_ci // The following code handles kExprI64AtomicCompareExchange. 10931cb0ef41Sopenharmony_ci 10941cb0ef41Sopenharmony_ci // We need {ebx} here, which is the root register. The root register it 10951cb0ef41Sopenharmony_ci // needs special treatment. As we use {ebx} directly in the code below, we 10961cb0ef41Sopenharmony_ci // have to make sure here that the root register is actually {ebx}. 10971cb0ef41Sopenharmony_ci static_assert(kRootRegister == ebx, 10981cb0ef41Sopenharmony_ci "The following code assumes that kRootRegister == ebx"); 10991cb0ef41Sopenharmony_ci push(kRootRegister); 11001cb0ef41Sopenharmony_ci 11011cb0ef41Sopenharmony_ci // The compare-exchange instruction uses registers as follows: 11021cb0ef41Sopenharmony_ci // old-value = EDX:EAX; new-value = ECX:EBX. 11031cb0ef41Sopenharmony_ci Register expected_hi = edx; 11041cb0ef41Sopenharmony_ci Register expected_lo = eax; 11051cb0ef41Sopenharmony_ci Register new_hi = ecx; 11061cb0ef41Sopenharmony_ci Register new_lo = ebx; 11071cb0ef41Sopenharmony_ci // The address needs a separate registers that does not alias with the 11081cb0ef41Sopenharmony_ci // ones above. 11091cb0ef41Sopenharmony_ci Register address = esi; 11101cb0ef41Sopenharmony_ci 11111cb0ef41Sopenharmony_ci // Spill all these registers if they are still holding other values. 11121cb0ef41Sopenharmony_ci SpillRegisters(expected_hi, expected_lo, new_hi, address); 11131cb0ef41Sopenharmony_ci 11141cb0ef41Sopenharmony_ci // We have to set new_lo specially, because it's the root register. We do it 11151cb0ef41Sopenharmony_ci // before setting all other registers so that the original value does not get 11161cb0ef41Sopenharmony_ci // overwritten. 11171cb0ef41Sopenharmony_ci mov(new_lo, new_value.low_gp()); 11181cb0ef41Sopenharmony_ci 11191cb0ef41Sopenharmony_ci // Move all other values into the right register. 11201cb0ef41Sopenharmony_ci ParallelRegisterMove( 11211cb0ef41Sopenharmony_ci {{LiftoffRegister(address), LiftoffRegister(dst_addr), kI32}, 11221cb0ef41Sopenharmony_ci {LiftoffRegister::ForPair(expected_lo, expected_hi), expected, kI64}, 11231cb0ef41Sopenharmony_ci {LiftoffRegister(new_hi), new_value.high(), kI32}}); 11241cb0ef41Sopenharmony_ci 11251cb0ef41Sopenharmony_ci Operand dst_op = Operand(address, offset_imm); 11261cb0ef41Sopenharmony_ci 11271cb0ef41Sopenharmony_ci lock(); 11281cb0ef41Sopenharmony_ci cmpxchg8b(dst_op); 11291cb0ef41Sopenharmony_ci 11301cb0ef41Sopenharmony_ci // Restore the root register, and we are done. 11311cb0ef41Sopenharmony_ci pop(kRootRegister); 11321cb0ef41Sopenharmony_ci 11331cb0ef41Sopenharmony_ci // Move the result into the correct registers. 11341cb0ef41Sopenharmony_ci ParallelRegisterMove( 11351cb0ef41Sopenharmony_ci {{result, LiftoffRegister::ForPair(expected_lo, expected_hi), kI64}}); 11361cb0ef41Sopenharmony_ci} 11371cb0ef41Sopenharmony_ci 11381cb0ef41Sopenharmony_civoid LiftoffAssembler::AtomicFence() { mfence(); } 11391cb0ef41Sopenharmony_ci 11401cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, 11411cb0ef41Sopenharmony_ci uint32_t caller_slot_idx, 11421cb0ef41Sopenharmony_ci ValueKind kind) { 11431cb0ef41Sopenharmony_ci liftoff::Load(this, dst, ebp, kSystemPointerSize * (caller_slot_idx + 1), 11441cb0ef41Sopenharmony_ci kind); 11451cb0ef41Sopenharmony_ci} 11461cb0ef41Sopenharmony_ci 11471cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister reg, int offset, 11481cb0ef41Sopenharmony_ci ValueKind kind) { 11491cb0ef41Sopenharmony_ci liftoff::Load(this, reg, esp, offset, kind); 11501cb0ef41Sopenharmony_ci} 11511cb0ef41Sopenharmony_ci 11521cb0ef41Sopenharmony_civoid LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, 11531cb0ef41Sopenharmony_ci uint32_t caller_slot_idx, 11541cb0ef41Sopenharmony_ci ValueKind kind) { 11551cb0ef41Sopenharmony_ci liftoff::Store(this, ebp, kSystemPointerSize * (caller_slot_idx + 1), src, 11561cb0ef41Sopenharmony_ci kind); 11571cb0ef41Sopenharmony_ci} 11581cb0ef41Sopenharmony_ci 11591cb0ef41Sopenharmony_civoid LiftoffAssembler::MoveStackValue(uint32_t dst_offset, uint32_t src_offset, 11601cb0ef41Sopenharmony_ci ValueKind kind) { 11611cb0ef41Sopenharmony_ci DCHECK_EQ(0, SlotSizeForType(kind) % kSystemPointerSize); 11621cb0ef41Sopenharmony_ci int words = SlotSizeForType(kind) / kSystemPointerSize; 11631cb0ef41Sopenharmony_ci DCHECK_LE(1, words); 11641cb0ef41Sopenharmony_ci // Make sure we move the words in the correct order in case there is an 11651cb0ef41Sopenharmony_ci // overlap between src and dst. 11661cb0ef41Sopenharmony_ci if (src_offset < dst_offset) { 11671cb0ef41Sopenharmony_ci do { 11681cb0ef41Sopenharmony_ci liftoff::MoveStackValue(this, liftoff::GetStackSlot(src_offset), 11691cb0ef41Sopenharmony_ci liftoff::GetStackSlot(dst_offset)); 11701cb0ef41Sopenharmony_ci dst_offset -= kSystemPointerSize; 11711cb0ef41Sopenharmony_ci src_offset -= kSystemPointerSize; 11721cb0ef41Sopenharmony_ci } while (--words); 11731cb0ef41Sopenharmony_ci } else { 11741cb0ef41Sopenharmony_ci while (words--) { 11751cb0ef41Sopenharmony_ci liftoff::MoveStackValue( 11761cb0ef41Sopenharmony_ci this, liftoff::GetStackSlot(src_offset - words * kSystemPointerSize), 11771cb0ef41Sopenharmony_ci liftoff::GetStackSlot(dst_offset - words * kSystemPointerSize)); 11781cb0ef41Sopenharmony_ci } 11791cb0ef41Sopenharmony_ci } 11801cb0ef41Sopenharmony_ci} 11811cb0ef41Sopenharmony_ci 11821cb0ef41Sopenharmony_civoid LiftoffAssembler::Move(Register dst, Register src, ValueKind kind) { 11831cb0ef41Sopenharmony_ci DCHECK_NE(dst, src); 11841cb0ef41Sopenharmony_ci DCHECK(kI32 == kind || is_reference(kind)); 11851cb0ef41Sopenharmony_ci mov(dst, src); 11861cb0ef41Sopenharmony_ci} 11871cb0ef41Sopenharmony_ci 11881cb0ef41Sopenharmony_civoid LiftoffAssembler::Move(DoubleRegister dst, DoubleRegister src, 11891cb0ef41Sopenharmony_ci ValueKind kind) { 11901cb0ef41Sopenharmony_ci DCHECK_NE(dst, src); 11911cb0ef41Sopenharmony_ci if (kind == kF32) { 11921cb0ef41Sopenharmony_ci movss(dst, src); 11931cb0ef41Sopenharmony_ci } else if (kind == kF64) { 11941cb0ef41Sopenharmony_ci movsd(dst, src); 11951cb0ef41Sopenharmony_ci } else { 11961cb0ef41Sopenharmony_ci DCHECK_EQ(kS128, kind); 11971cb0ef41Sopenharmony_ci Movaps(dst, src); 11981cb0ef41Sopenharmony_ci } 11991cb0ef41Sopenharmony_ci} 12001cb0ef41Sopenharmony_ci 12011cb0ef41Sopenharmony_civoid LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueKind kind) { 12021cb0ef41Sopenharmony_ci RecordUsedSpillOffset(offset); 12031cb0ef41Sopenharmony_ci Operand dst = liftoff::GetStackSlot(offset); 12041cb0ef41Sopenharmony_ci switch (kind) { 12051cb0ef41Sopenharmony_ci case kI32: 12061cb0ef41Sopenharmony_ci case kOptRef: 12071cb0ef41Sopenharmony_ci case kRef: 12081cb0ef41Sopenharmony_ci case kRtt: 12091cb0ef41Sopenharmony_ci mov(dst, reg.gp()); 12101cb0ef41Sopenharmony_ci break; 12111cb0ef41Sopenharmony_ci case kI64: 12121cb0ef41Sopenharmony_ci mov(liftoff::GetHalfStackSlot(offset, kLowWord), reg.low_gp()); 12131cb0ef41Sopenharmony_ci mov(liftoff::GetHalfStackSlot(offset, kHighWord), reg.high_gp()); 12141cb0ef41Sopenharmony_ci break; 12151cb0ef41Sopenharmony_ci case kF32: 12161cb0ef41Sopenharmony_ci movss(dst, reg.fp()); 12171cb0ef41Sopenharmony_ci break; 12181cb0ef41Sopenharmony_ci case kF64: 12191cb0ef41Sopenharmony_ci movsd(dst, reg.fp()); 12201cb0ef41Sopenharmony_ci break; 12211cb0ef41Sopenharmony_ci case kS128: 12221cb0ef41Sopenharmony_ci movdqu(dst, reg.fp()); 12231cb0ef41Sopenharmony_ci break; 12241cb0ef41Sopenharmony_ci default: 12251cb0ef41Sopenharmony_ci UNREACHABLE(); 12261cb0ef41Sopenharmony_ci } 12271cb0ef41Sopenharmony_ci} 12281cb0ef41Sopenharmony_ci 12291cb0ef41Sopenharmony_civoid LiftoffAssembler::Spill(int offset, WasmValue value) { 12301cb0ef41Sopenharmony_ci RecordUsedSpillOffset(offset); 12311cb0ef41Sopenharmony_ci Operand dst = liftoff::GetStackSlot(offset); 12321cb0ef41Sopenharmony_ci switch (value.type().kind()) { 12331cb0ef41Sopenharmony_ci case kI32: 12341cb0ef41Sopenharmony_ci mov(dst, Immediate(value.to_i32())); 12351cb0ef41Sopenharmony_ci break; 12361cb0ef41Sopenharmony_ci case kI64: { 12371cb0ef41Sopenharmony_ci int32_t low_word = value.to_i64(); 12381cb0ef41Sopenharmony_ci int32_t high_word = value.to_i64() >> 32; 12391cb0ef41Sopenharmony_ci mov(liftoff::GetHalfStackSlot(offset, kLowWord), Immediate(low_word)); 12401cb0ef41Sopenharmony_ci mov(liftoff::GetHalfStackSlot(offset, kHighWord), Immediate(high_word)); 12411cb0ef41Sopenharmony_ci break; 12421cb0ef41Sopenharmony_ci } 12431cb0ef41Sopenharmony_ci default: 12441cb0ef41Sopenharmony_ci // We do not track f32 and f64 constants, hence they are unreachable. 12451cb0ef41Sopenharmony_ci UNREACHABLE(); 12461cb0ef41Sopenharmony_ci } 12471cb0ef41Sopenharmony_ci} 12481cb0ef41Sopenharmony_ci 12491cb0ef41Sopenharmony_civoid LiftoffAssembler::Fill(LiftoffRegister reg, int offset, ValueKind kind) { 12501cb0ef41Sopenharmony_ci liftoff::Load(this, reg, ebp, -offset, kind); 12511cb0ef41Sopenharmony_ci} 12521cb0ef41Sopenharmony_ci 12531cb0ef41Sopenharmony_civoid LiftoffAssembler::FillI64Half(Register reg, int offset, RegPairHalf half) { 12541cb0ef41Sopenharmony_ci mov(reg, liftoff::GetHalfStackSlot(offset, half)); 12551cb0ef41Sopenharmony_ci} 12561cb0ef41Sopenharmony_ci 12571cb0ef41Sopenharmony_civoid LiftoffAssembler::FillStackSlotsWithZero(int start, int size) { 12581cb0ef41Sopenharmony_ci DCHECK_LT(0, size); 12591cb0ef41Sopenharmony_ci DCHECK_EQ(0, size % 4); 12601cb0ef41Sopenharmony_ci RecordUsedSpillOffset(start + size); 12611cb0ef41Sopenharmony_ci 12621cb0ef41Sopenharmony_ci if (size <= 12) { 12631cb0ef41Sopenharmony_ci // Special straight-line code for up to three words (6-9 bytes per word: 12641cb0ef41Sopenharmony_ci // C7 <1-4 bytes operand> <4 bytes imm>, makes 18-27 bytes total). 12651cb0ef41Sopenharmony_ci for (int offset = 4; offset <= size; offset += 4) { 12661cb0ef41Sopenharmony_ci mov(liftoff::GetHalfStackSlot(start + offset, kLowWord), Immediate(0)); 12671cb0ef41Sopenharmony_ci } 12681cb0ef41Sopenharmony_ci } else { 12691cb0ef41Sopenharmony_ci // General case for bigger counts. 12701cb0ef41Sopenharmony_ci // This sequence takes 19-22 bytes (3 for pushes, 3-6 for lea, 2 for xor, 5 12711cb0ef41Sopenharmony_ci // for mov, 3 for repstosq, 3 for pops). 12721cb0ef41Sopenharmony_ci // Note: rep_stos fills ECX doublewords at [EDI] with EAX. 12731cb0ef41Sopenharmony_ci push(eax); 12741cb0ef41Sopenharmony_ci push(ecx); 12751cb0ef41Sopenharmony_ci push(edi); 12761cb0ef41Sopenharmony_ci lea(edi, liftoff::GetStackSlot(start + size)); 12771cb0ef41Sopenharmony_ci xor_(eax, eax); 12781cb0ef41Sopenharmony_ci // Size is in bytes, convert to doublewords (4-bytes). 12791cb0ef41Sopenharmony_ci mov(ecx, Immediate(size / 4)); 12801cb0ef41Sopenharmony_ci rep_stos(); 12811cb0ef41Sopenharmony_ci pop(edi); 12821cb0ef41Sopenharmony_ci pop(ecx); 12831cb0ef41Sopenharmony_ci pop(eax); 12841cb0ef41Sopenharmony_ci } 12851cb0ef41Sopenharmony_ci} 12861cb0ef41Sopenharmony_ci 12871cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_add(Register dst, Register lhs, Register rhs) { 12881cb0ef41Sopenharmony_ci if (lhs != dst) { 12891cb0ef41Sopenharmony_ci lea(dst, Operand(lhs, rhs, times_1, 0)); 12901cb0ef41Sopenharmony_ci } else { 12911cb0ef41Sopenharmony_ci add(dst, rhs); 12921cb0ef41Sopenharmony_ci } 12931cb0ef41Sopenharmony_ci} 12941cb0ef41Sopenharmony_ci 12951cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_addi(Register dst, Register lhs, int32_t imm) { 12961cb0ef41Sopenharmony_ci if (lhs != dst) { 12971cb0ef41Sopenharmony_ci lea(dst, Operand(lhs, imm)); 12981cb0ef41Sopenharmony_ci } else { 12991cb0ef41Sopenharmony_ci add(dst, Immediate(imm)); 13001cb0ef41Sopenharmony_ci } 13011cb0ef41Sopenharmony_ci} 13021cb0ef41Sopenharmony_ci 13031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_sub(Register dst, Register lhs, Register rhs) { 13041cb0ef41Sopenharmony_ci if (dst != rhs) { 13051cb0ef41Sopenharmony_ci // Default path. 13061cb0ef41Sopenharmony_ci if (dst != lhs) mov(dst, lhs); 13071cb0ef41Sopenharmony_ci sub(dst, rhs); 13081cb0ef41Sopenharmony_ci } else if (lhs == rhs) { 13091cb0ef41Sopenharmony_ci // Degenerate case. 13101cb0ef41Sopenharmony_ci xor_(dst, dst); 13111cb0ef41Sopenharmony_ci } else { 13121cb0ef41Sopenharmony_ci // Emit {dst = lhs + -rhs} if dst == rhs. 13131cb0ef41Sopenharmony_ci neg(dst); 13141cb0ef41Sopenharmony_ci add(dst, lhs); 13151cb0ef41Sopenharmony_ci } 13161cb0ef41Sopenharmony_ci} 13171cb0ef41Sopenharmony_ci 13181cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_subi(Register dst, Register lhs, int32_t imm) { 13191cb0ef41Sopenharmony_ci if (dst != lhs) { 13201cb0ef41Sopenharmony_ci // We'll have to implement an UB-safe version if we need this corner case. 13211cb0ef41Sopenharmony_ci DCHECK_NE(imm, kMinInt); 13221cb0ef41Sopenharmony_ci lea(dst, Operand(lhs, -imm)); 13231cb0ef41Sopenharmony_ci } else { 13241cb0ef41Sopenharmony_ci sub(dst, Immediate(imm)); 13251cb0ef41Sopenharmony_ci } 13261cb0ef41Sopenharmony_ci} 13271cb0ef41Sopenharmony_ci 13281cb0ef41Sopenharmony_cinamespace liftoff { 13291cb0ef41Sopenharmony_citemplate <void (Assembler::*op)(Register, Register)> 13301cb0ef41Sopenharmony_civoid EmitCommutativeBinOp(LiftoffAssembler* assm, Register dst, Register lhs, 13311cb0ef41Sopenharmony_ci Register rhs) { 13321cb0ef41Sopenharmony_ci if (dst == rhs) { 13331cb0ef41Sopenharmony_ci (assm->*op)(dst, lhs); 13341cb0ef41Sopenharmony_ci } else { 13351cb0ef41Sopenharmony_ci if (dst != lhs) assm->mov(dst, lhs); 13361cb0ef41Sopenharmony_ci (assm->*op)(dst, rhs); 13371cb0ef41Sopenharmony_ci } 13381cb0ef41Sopenharmony_ci} 13391cb0ef41Sopenharmony_ci 13401cb0ef41Sopenharmony_citemplate <void (Assembler::*op)(Register, int32_t)> 13411cb0ef41Sopenharmony_civoid EmitCommutativeBinOpImm(LiftoffAssembler* assm, Register dst, Register lhs, 13421cb0ef41Sopenharmony_ci int32_t imm) { 13431cb0ef41Sopenharmony_ci if (dst != lhs) assm->mov(dst, lhs); 13441cb0ef41Sopenharmony_ci (assm->*op)(dst, imm); 13451cb0ef41Sopenharmony_ci} 13461cb0ef41Sopenharmony_ci} // namespace liftoff 13471cb0ef41Sopenharmony_ci 13481cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_mul(Register dst, Register lhs, Register rhs) { 13491cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOp<&Assembler::imul>(this, dst, lhs, rhs); 13501cb0ef41Sopenharmony_ci} 13511cb0ef41Sopenharmony_ci 13521cb0ef41Sopenharmony_cinamespace liftoff { 13531cb0ef41Sopenharmony_cienum class DivOrRem : uint8_t { kDiv, kRem }; 13541cb0ef41Sopenharmony_citemplate <bool is_signed, DivOrRem div_or_rem> 13551cb0ef41Sopenharmony_civoid EmitInt32DivOrRem(LiftoffAssembler* assm, Register dst, Register lhs, 13561cb0ef41Sopenharmony_ci Register rhs, Label* trap_div_by_zero, 13571cb0ef41Sopenharmony_ci Label* trap_div_unrepresentable) { 13581cb0ef41Sopenharmony_ci constexpr bool needs_unrepresentable_check = 13591cb0ef41Sopenharmony_ci is_signed && div_or_rem == DivOrRem::kDiv; 13601cb0ef41Sopenharmony_ci constexpr bool special_case_minus_1 = 13611cb0ef41Sopenharmony_ci is_signed && div_or_rem == DivOrRem::kRem; 13621cb0ef41Sopenharmony_ci DCHECK_EQ(needs_unrepresentable_check, trap_div_unrepresentable != nullptr); 13631cb0ef41Sopenharmony_ci 13641cb0ef41Sopenharmony_ci // For division, the lhs is always taken from {edx:eax}. Thus, make sure that 13651cb0ef41Sopenharmony_ci // these registers are unused. If {rhs} is stored in one of them, move it to 13661cb0ef41Sopenharmony_ci // another temporary register. 13671cb0ef41Sopenharmony_ci // Do all this before any branch, such that the code is executed 13681cb0ef41Sopenharmony_ci // unconditionally, as the cache state will also be modified unconditionally. 13691cb0ef41Sopenharmony_ci assm->SpillRegisters(eax, edx); 13701cb0ef41Sopenharmony_ci if (rhs == eax || rhs == edx) { 13711cb0ef41Sopenharmony_ci LiftoffRegList unavailable{eax, edx, lhs}; 13721cb0ef41Sopenharmony_ci Register tmp = assm->GetUnusedRegister(kGpReg, unavailable).gp(); 13731cb0ef41Sopenharmony_ci assm->mov(tmp, rhs); 13741cb0ef41Sopenharmony_ci rhs = tmp; 13751cb0ef41Sopenharmony_ci } 13761cb0ef41Sopenharmony_ci 13771cb0ef41Sopenharmony_ci // Check for division by zero. 13781cb0ef41Sopenharmony_ci assm->test(rhs, rhs); 13791cb0ef41Sopenharmony_ci assm->j(zero, trap_div_by_zero); 13801cb0ef41Sopenharmony_ci 13811cb0ef41Sopenharmony_ci Label done; 13821cb0ef41Sopenharmony_ci if (needs_unrepresentable_check) { 13831cb0ef41Sopenharmony_ci // Check for {kMinInt / -1}. This is unrepresentable. 13841cb0ef41Sopenharmony_ci Label do_div; 13851cb0ef41Sopenharmony_ci assm->cmp(rhs, -1); 13861cb0ef41Sopenharmony_ci assm->j(not_equal, &do_div); 13871cb0ef41Sopenharmony_ci assm->cmp(lhs, kMinInt); 13881cb0ef41Sopenharmony_ci assm->j(equal, trap_div_unrepresentable); 13891cb0ef41Sopenharmony_ci assm->bind(&do_div); 13901cb0ef41Sopenharmony_ci } else if (special_case_minus_1) { 13911cb0ef41Sopenharmony_ci // {lhs % -1} is always 0 (needs to be special cased because {kMinInt / -1} 13921cb0ef41Sopenharmony_ci // cannot be computed). 13931cb0ef41Sopenharmony_ci Label do_rem; 13941cb0ef41Sopenharmony_ci assm->cmp(rhs, -1); 13951cb0ef41Sopenharmony_ci assm->j(not_equal, &do_rem); 13961cb0ef41Sopenharmony_ci assm->xor_(dst, dst); 13971cb0ef41Sopenharmony_ci assm->jmp(&done); 13981cb0ef41Sopenharmony_ci assm->bind(&do_rem); 13991cb0ef41Sopenharmony_ci } 14001cb0ef41Sopenharmony_ci 14011cb0ef41Sopenharmony_ci // Now move {lhs} into {eax}, then zero-extend or sign-extend into {edx}, then 14021cb0ef41Sopenharmony_ci // do the division. 14031cb0ef41Sopenharmony_ci if (lhs != eax) assm->mov(eax, lhs); 14041cb0ef41Sopenharmony_ci if (is_signed) { 14051cb0ef41Sopenharmony_ci assm->cdq(); 14061cb0ef41Sopenharmony_ci assm->idiv(rhs); 14071cb0ef41Sopenharmony_ci } else { 14081cb0ef41Sopenharmony_ci assm->xor_(edx, edx); 14091cb0ef41Sopenharmony_ci assm->div(rhs); 14101cb0ef41Sopenharmony_ci } 14111cb0ef41Sopenharmony_ci 14121cb0ef41Sopenharmony_ci // Move back the result (in {eax} or {edx}) into the {dst} register. 14131cb0ef41Sopenharmony_ci constexpr Register kResultReg = div_or_rem == DivOrRem::kDiv ? eax : edx; 14141cb0ef41Sopenharmony_ci if (dst != kResultReg) assm->mov(dst, kResultReg); 14151cb0ef41Sopenharmony_ci if (special_case_minus_1) assm->bind(&done); 14161cb0ef41Sopenharmony_ci} 14171cb0ef41Sopenharmony_ci} // namespace liftoff 14181cb0ef41Sopenharmony_ci 14191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_divs(Register dst, Register lhs, Register rhs, 14201cb0ef41Sopenharmony_ci Label* trap_div_by_zero, 14211cb0ef41Sopenharmony_ci Label* trap_div_unrepresentable) { 14221cb0ef41Sopenharmony_ci liftoff::EmitInt32DivOrRem<true, liftoff::DivOrRem::kDiv>( 14231cb0ef41Sopenharmony_ci this, dst, lhs, rhs, trap_div_by_zero, trap_div_unrepresentable); 14241cb0ef41Sopenharmony_ci} 14251cb0ef41Sopenharmony_ci 14261cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_divu(Register dst, Register lhs, Register rhs, 14271cb0ef41Sopenharmony_ci Label* trap_div_by_zero) { 14281cb0ef41Sopenharmony_ci liftoff::EmitInt32DivOrRem<false, liftoff::DivOrRem::kDiv>( 14291cb0ef41Sopenharmony_ci this, dst, lhs, rhs, trap_div_by_zero, nullptr); 14301cb0ef41Sopenharmony_ci} 14311cb0ef41Sopenharmony_ci 14321cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_rems(Register dst, Register lhs, Register rhs, 14331cb0ef41Sopenharmony_ci Label* trap_div_by_zero) { 14341cb0ef41Sopenharmony_ci liftoff::EmitInt32DivOrRem<true, liftoff::DivOrRem::kRem>( 14351cb0ef41Sopenharmony_ci this, dst, lhs, rhs, trap_div_by_zero, nullptr); 14361cb0ef41Sopenharmony_ci} 14371cb0ef41Sopenharmony_ci 14381cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_remu(Register dst, Register lhs, Register rhs, 14391cb0ef41Sopenharmony_ci Label* trap_div_by_zero) { 14401cb0ef41Sopenharmony_ci liftoff::EmitInt32DivOrRem<false, liftoff::DivOrRem::kRem>( 14411cb0ef41Sopenharmony_ci this, dst, lhs, rhs, trap_div_by_zero, nullptr); 14421cb0ef41Sopenharmony_ci} 14431cb0ef41Sopenharmony_ci 14441cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_and(Register dst, Register lhs, Register rhs) { 14451cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOp<&Assembler::and_>(this, dst, lhs, rhs); 14461cb0ef41Sopenharmony_ci} 14471cb0ef41Sopenharmony_ci 14481cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_andi(Register dst, Register lhs, int32_t imm) { 14491cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOpImm<&Assembler::and_>(this, dst, lhs, imm); 14501cb0ef41Sopenharmony_ci} 14511cb0ef41Sopenharmony_ci 14521cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_or(Register dst, Register lhs, Register rhs) { 14531cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOp<&Assembler::or_>(this, dst, lhs, rhs); 14541cb0ef41Sopenharmony_ci} 14551cb0ef41Sopenharmony_ci 14561cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_ori(Register dst, Register lhs, int32_t imm) { 14571cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOpImm<&Assembler::or_>(this, dst, lhs, imm); 14581cb0ef41Sopenharmony_ci} 14591cb0ef41Sopenharmony_ci 14601cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_xor(Register dst, Register lhs, Register rhs) { 14611cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOp<&Assembler::xor_>(this, dst, lhs, rhs); 14621cb0ef41Sopenharmony_ci} 14631cb0ef41Sopenharmony_ci 14641cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_xori(Register dst, Register lhs, int32_t imm) { 14651cb0ef41Sopenharmony_ci liftoff::EmitCommutativeBinOpImm<&Assembler::xor_>(this, dst, lhs, imm); 14661cb0ef41Sopenharmony_ci} 14671cb0ef41Sopenharmony_ci 14681cb0ef41Sopenharmony_cinamespace liftoff { 14691cb0ef41Sopenharmony_ciinline void EmitShiftOperation(LiftoffAssembler* assm, Register dst, 14701cb0ef41Sopenharmony_ci Register src, Register amount, 14711cb0ef41Sopenharmony_ci void (Assembler::*emit_shift)(Register)) { 14721cb0ef41Sopenharmony_ci LiftoffRegList pinned = {dst, src, amount}; 14731cb0ef41Sopenharmony_ci // If dst is ecx, compute into a tmp register first, then move to ecx. 14741cb0ef41Sopenharmony_ci if (dst == ecx) { 14751cb0ef41Sopenharmony_ci Register tmp = assm->GetUnusedRegister(kGpReg, pinned).gp(); 14761cb0ef41Sopenharmony_ci assm->mov(tmp, src); 14771cb0ef41Sopenharmony_ci if (amount != ecx) assm->mov(ecx, amount); 14781cb0ef41Sopenharmony_ci (assm->*emit_shift)(tmp); 14791cb0ef41Sopenharmony_ci assm->mov(ecx, tmp); 14801cb0ef41Sopenharmony_ci return; 14811cb0ef41Sopenharmony_ci } 14821cb0ef41Sopenharmony_ci 14831cb0ef41Sopenharmony_ci // Move amount into ecx. If ecx is in use, move its content to a tmp register 14841cb0ef41Sopenharmony_ci // first. If src is ecx, src is now the tmp register. 14851cb0ef41Sopenharmony_ci Register tmp_reg = no_reg; 14861cb0ef41Sopenharmony_ci if (amount != ecx) { 14871cb0ef41Sopenharmony_ci if (assm->cache_state()->is_used(LiftoffRegister(ecx)) || 14881cb0ef41Sopenharmony_ci pinned.has(LiftoffRegister(ecx))) { 14891cb0ef41Sopenharmony_ci tmp_reg = assm->GetUnusedRegister(kGpReg, pinned).gp(); 14901cb0ef41Sopenharmony_ci assm->mov(tmp_reg, ecx); 14911cb0ef41Sopenharmony_ci if (src == ecx) src = tmp_reg; 14921cb0ef41Sopenharmony_ci } 14931cb0ef41Sopenharmony_ci assm->mov(ecx, amount); 14941cb0ef41Sopenharmony_ci } 14951cb0ef41Sopenharmony_ci 14961cb0ef41Sopenharmony_ci // Do the actual shift. 14971cb0ef41Sopenharmony_ci if (dst != src) assm->mov(dst, src); 14981cb0ef41Sopenharmony_ci (assm->*emit_shift)(dst); 14991cb0ef41Sopenharmony_ci 15001cb0ef41Sopenharmony_ci // Restore ecx if needed. 15011cb0ef41Sopenharmony_ci if (tmp_reg.is_valid()) assm->mov(ecx, tmp_reg); 15021cb0ef41Sopenharmony_ci} 15031cb0ef41Sopenharmony_ci} // namespace liftoff 15041cb0ef41Sopenharmony_ci 15051cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_shl(Register dst, Register src, 15061cb0ef41Sopenharmony_ci Register amount) { 15071cb0ef41Sopenharmony_ci liftoff::EmitShiftOperation(this, dst, src, amount, &Assembler::shl_cl); 15081cb0ef41Sopenharmony_ci} 15091cb0ef41Sopenharmony_ci 15101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_shli(Register dst, Register src, 15111cb0ef41Sopenharmony_ci int32_t amount) { 15121cb0ef41Sopenharmony_ci if (dst != src) mov(dst, src); 15131cb0ef41Sopenharmony_ci shl(dst, amount & 31); 15141cb0ef41Sopenharmony_ci} 15151cb0ef41Sopenharmony_ci 15161cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_sar(Register dst, Register src, 15171cb0ef41Sopenharmony_ci Register amount) { 15181cb0ef41Sopenharmony_ci liftoff::EmitShiftOperation(this, dst, src, amount, &Assembler::sar_cl); 15191cb0ef41Sopenharmony_ci} 15201cb0ef41Sopenharmony_ci 15211cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_sari(Register dst, Register src, 15221cb0ef41Sopenharmony_ci int32_t amount) { 15231cb0ef41Sopenharmony_ci if (dst != src) mov(dst, src); 15241cb0ef41Sopenharmony_ci sar(dst, amount & 31); 15251cb0ef41Sopenharmony_ci} 15261cb0ef41Sopenharmony_ci 15271cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_shr(Register dst, Register src, 15281cb0ef41Sopenharmony_ci Register amount) { 15291cb0ef41Sopenharmony_ci liftoff::EmitShiftOperation(this, dst, src, amount, &Assembler::shr_cl); 15301cb0ef41Sopenharmony_ci} 15311cb0ef41Sopenharmony_ci 15321cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_shri(Register dst, Register src, 15331cb0ef41Sopenharmony_ci int32_t amount) { 15341cb0ef41Sopenharmony_ci if (dst != src) mov(dst, src); 15351cb0ef41Sopenharmony_ci shr(dst, amount & 31); 15361cb0ef41Sopenharmony_ci} 15371cb0ef41Sopenharmony_ci 15381cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_clz(Register dst, Register src) { 15391cb0ef41Sopenharmony_ci Lzcnt(dst, src); 15401cb0ef41Sopenharmony_ci} 15411cb0ef41Sopenharmony_ci 15421cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_ctz(Register dst, Register src) { 15431cb0ef41Sopenharmony_ci Tzcnt(dst, src); 15441cb0ef41Sopenharmony_ci} 15451cb0ef41Sopenharmony_ci 15461cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { 15471cb0ef41Sopenharmony_ci if (!CpuFeatures::IsSupported(POPCNT)) return false; 15481cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, POPCNT); 15491cb0ef41Sopenharmony_ci popcnt(dst, src); 15501cb0ef41Sopenharmony_ci return true; 15511cb0ef41Sopenharmony_ci} 15521cb0ef41Sopenharmony_ci 15531cb0ef41Sopenharmony_cinamespace liftoff { 15541cb0ef41Sopenharmony_citemplate <void (Assembler::*op)(Register, Register), 15551cb0ef41Sopenharmony_ci void (Assembler::*op_with_carry)(Register, Register)> 15561cb0ef41Sopenharmony_ciinline void OpWithCarry(LiftoffAssembler* assm, LiftoffRegister dst, 15571cb0ef41Sopenharmony_ci LiftoffRegister lhs, LiftoffRegister rhs) { 15581cb0ef41Sopenharmony_ci // First, compute the low half of the result, potentially into a temporary dst 15591cb0ef41Sopenharmony_ci // register if {dst.low_gp()} equals {rhs.low_gp()} or any register we need to 15601cb0ef41Sopenharmony_ci // keep alive for computing the upper half. 15611cb0ef41Sopenharmony_ci LiftoffRegList keep_alive{lhs.high_gp(), rhs}; 15621cb0ef41Sopenharmony_ci Register dst_low = keep_alive.has(dst.low_gp()) 15631cb0ef41Sopenharmony_ci ? assm->GetUnusedRegister(kGpReg, keep_alive).gp() 15641cb0ef41Sopenharmony_ci : dst.low_gp(); 15651cb0ef41Sopenharmony_ci 15661cb0ef41Sopenharmony_ci if (dst_low != lhs.low_gp()) assm->mov(dst_low, lhs.low_gp()); 15671cb0ef41Sopenharmony_ci (assm->*op)(dst_low, rhs.low_gp()); 15681cb0ef41Sopenharmony_ci 15691cb0ef41Sopenharmony_ci // Now compute the upper half, while keeping alive the previous result. 15701cb0ef41Sopenharmony_ci keep_alive = LiftoffRegList{dst_low, rhs.high_gp()}; 15711cb0ef41Sopenharmony_ci Register dst_high = keep_alive.has(dst.high_gp()) 15721cb0ef41Sopenharmony_ci ? assm->GetUnusedRegister(kGpReg, keep_alive).gp() 15731cb0ef41Sopenharmony_ci : dst.high_gp(); 15741cb0ef41Sopenharmony_ci 15751cb0ef41Sopenharmony_ci if (dst_high != lhs.high_gp()) assm->mov(dst_high, lhs.high_gp()); 15761cb0ef41Sopenharmony_ci (assm->*op_with_carry)(dst_high, rhs.high_gp()); 15771cb0ef41Sopenharmony_ci 15781cb0ef41Sopenharmony_ci // If necessary, move result into the right registers. 15791cb0ef41Sopenharmony_ci LiftoffRegister tmp_result = LiftoffRegister::ForPair(dst_low, dst_high); 15801cb0ef41Sopenharmony_ci if (tmp_result != dst) assm->Move(dst, tmp_result, kI64); 15811cb0ef41Sopenharmony_ci} 15821cb0ef41Sopenharmony_ci 15831cb0ef41Sopenharmony_citemplate <void (Assembler::*op)(Register, const Immediate&), 15841cb0ef41Sopenharmony_ci void (Assembler::*op_with_carry)(Register, int32_t)> 15851cb0ef41Sopenharmony_ciinline void OpWithCarryI(LiftoffAssembler* assm, LiftoffRegister dst, 15861cb0ef41Sopenharmony_ci LiftoffRegister lhs, int64_t imm) { 15871cb0ef41Sopenharmony_ci // The compiler allocated registers such that either {dst == lhs} or there is 15881cb0ef41Sopenharmony_ci // no overlap between the two. 15891cb0ef41Sopenharmony_ci DCHECK_NE(dst.low_gp(), lhs.high_gp()); 15901cb0ef41Sopenharmony_ci 15911cb0ef41Sopenharmony_ci int32_t imm_low_word = static_cast<int32_t>(imm); 15921cb0ef41Sopenharmony_ci int32_t imm_high_word = static_cast<int32_t>(imm >> 32); 15931cb0ef41Sopenharmony_ci 15941cb0ef41Sopenharmony_ci // First, compute the low half of the result. 15951cb0ef41Sopenharmony_ci if (dst.low_gp() != lhs.low_gp()) assm->mov(dst.low_gp(), lhs.low_gp()); 15961cb0ef41Sopenharmony_ci (assm->*op)(dst.low_gp(), Immediate(imm_low_word)); 15971cb0ef41Sopenharmony_ci 15981cb0ef41Sopenharmony_ci // Now compute the upper half. 15991cb0ef41Sopenharmony_ci if (dst.high_gp() != lhs.high_gp()) assm->mov(dst.high_gp(), lhs.high_gp()); 16001cb0ef41Sopenharmony_ci (assm->*op_with_carry)(dst.high_gp(), imm_high_word); 16011cb0ef41Sopenharmony_ci} 16021cb0ef41Sopenharmony_ci} // namespace liftoff 16031cb0ef41Sopenharmony_ci 16041cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_add(LiftoffRegister dst, LiftoffRegister lhs, 16051cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 16061cb0ef41Sopenharmony_ci liftoff::OpWithCarry<&Assembler::add, &Assembler::adc>(this, dst, lhs, rhs); 16071cb0ef41Sopenharmony_ci} 16081cb0ef41Sopenharmony_ci 16091cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_addi(LiftoffRegister dst, LiftoffRegister lhs, 16101cb0ef41Sopenharmony_ci int64_t imm) { 16111cb0ef41Sopenharmony_ci liftoff::OpWithCarryI<&Assembler::add, &Assembler::adc>(this, dst, lhs, imm); 16121cb0ef41Sopenharmony_ci} 16131cb0ef41Sopenharmony_ci 16141cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_sub(LiftoffRegister dst, LiftoffRegister lhs, 16151cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 16161cb0ef41Sopenharmony_ci liftoff::OpWithCarry<&Assembler::sub, &Assembler::sbb>(this, dst, lhs, rhs); 16171cb0ef41Sopenharmony_ci} 16181cb0ef41Sopenharmony_ci 16191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs, 16201cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 16211cb0ef41Sopenharmony_ci // Idea: 16221cb0ef41Sopenharmony_ci // [ lhs_hi | lhs_lo ] * [ rhs_hi | rhs_lo ] 16231cb0ef41Sopenharmony_ci // = [ lhs_hi * rhs_lo | ] (32 bit mul, shift 32) 16241cb0ef41Sopenharmony_ci // + [ lhs_lo * rhs_hi | ] (32 bit mul, shift 32) 16251cb0ef41Sopenharmony_ci // + [ lhs_lo * rhs_lo ] (32x32->64 mul, shift 0) 16261cb0ef41Sopenharmony_ci 16271cb0ef41Sopenharmony_ci // For simplicity, we move lhs and rhs into fixed registers. 16281cb0ef41Sopenharmony_ci Register dst_hi = edx; 16291cb0ef41Sopenharmony_ci Register dst_lo = eax; 16301cb0ef41Sopenharmony_ci Register lhs_hi = ecx; 16311cb0ef41Sopenharmony_ci Register lhs_lo = dst_lo; 16321cb0ef41Sopenharmony_ci Register rhs_hi = dst_hi; 16331cb0ef41Sopenharmony_ci Register rhs_lo = esi; 16341cb0ef41Sopenharmony_ci 16351cb0ef41Sopenharmony_ci // Spill all these registers if they are still holding other values. 16361cb0ef41Sopenharmony_ci SpillRegisters(dst_hi, dst_lo, lhs_hi, rhs_lo); 16371cb0ef41Sopenharmony_ci 16381cb0ef41Sopenharmony_ci // Move lhs and rhs into the respective registers. 16391cb0ef41Sopenharmony_ci ParallelRegisterMove({{LiftoffRegister::ForPair(lhs_lo, lhs_hi), lhs, kI64}, 16401cb0ef41Sopenharmony_ci {LiftoffRegister::ForPair(rhs_lo, rhs_hi), rhs, kI64}}); 16411cb0ef41Sopenharmony_ci 16421cb0ef41Sopenharmony_ci // First mul: lhs_hi' = lhs_hi * rhs_lo. 16431cb0ef41Sopenharmony_ci imul(lhs_hi, rhs_lo); 16441cb0ef41Sopenharmony_ci // Second mul: rhi_hi' = rhs_hi * lhs_lo. 16451cb0ef41Sopenharmony_ci imul(rhs_hi, lhs_lo); 16461cb0ef41Sopenharmony_ci // Add them: lhs_hi'' = lhs_hi' + rhs_hi' = lhs_hi * rhs_lo + rhs_hi * lhs_lo. 16471cb0ef41Sopenharmony_ci add(lhs_hi, rhs_hi); 16481cb0ef41Sopenharmony_ci // Third mul: edx:eax (dst_hi:dst_lo) = eax * esi (lhs_lo * rhs_lo). 16491cb0ef41Sopenharmony_ci mul(rhs_lo); 16501cb0ef41Sopenharmony_ci // Add lhs_hi'' to dst_hi. 16511cb0ef41Sopenharmony_ci add(dst_hi, lhs_hi); 16521cb0ef41Sopenharmony_ci 16531cb0ef41Sopenharmony_ci // Finally, move back the temporary result to the actual dst register pair. 16541cb0ef41Sopenharmony_ci LiftoffRegister dst_tmp = LiftoffRegister::ForPair(dst_lo, dst_hi); 16551cb0ef41Sopenharmony_ci if (dst != dst_tmp) Move(dst, dst_tmp, kI64); 16561cb0ef41Sopenharmony_ci} 16571cb0ef41Sopenharmony_ci 16581cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs, 16591cb0ef41Sopenharmony_ci LiftoffRegister rhs, 16601cb0ef41Sopenharmony_ci Label* trap_div_by_zero, 16611cb0ef41Sopenharmony_ci Label* trap_div_unrepresentable) { 16621cb0ef41Sopenharmony_ci return false; 16631cb0ef41Sopenharmony_ci} 16641cb0ef41Sopenharmony_ci 16651cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs, 16661cb0ef41Sopenharmony_ci LiftoffRegister rhs, 16671cb0ef41Sopenharmony_ci Label* trap_div_by_zero) { 16681cb0ef41Sopenharmony_ci return false; 16691cb0ef41Sopenharmony_ci} 16701cb0ef41Sopenharmony_ci 16711cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs, 16721cb0ef41Sopenharmony_ci LiftoffRegister rhs, 16731cb0ef41Sopenharmony_ci Label* trap_div_by_zero) { 16741cb0ef41Sopenharmony_ci return false; 16751cb0ef41Sopenharmony_ci} 16761cb0ef41Sopenharmony_ci 16771cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs, 16781cb0ef41Sopenharmony_ci LiftoffRegister rhs, 16791cb0ef41Sopenharmony_ci Label* trap_div_by_zero) { 16801cb0ef41Sopenharmony_ci return false; 16811cb0ef41Sopenharmony_ci} 16821cb0ef41Sopenharmony_ci 16831cb0ef41Sopenharmony_cinamespace liftoff { 16841cb0ef41Sopenharmony_ciinline bool PairContains(LiftoffRegister pair, Register reg) { 16851cb0ef41Sopenharmony_ci return pair.low_gp() == reg || pair.high_gp() == reg; 16861cb0ef41Sopenharmony_ci} 16871cb0ef41Sopenharmony_ci 16881cb0ef41Sopenharmony_ciinline LiftoffRegister ReplaceInPair(LiftoffRegister pair, Register old_reg, 16891cb0ef41Sopenharmony_ci Register new_reg) { 16901cb0ef41Sopenharmony_ci if (pair.low_gp() == old_reg) { 16911cb0ef41Sopenharmony_ci return LiftoffRegister::ForPair(new_reg, pair.high_gp()); 16921cb0ef41Sopenharmony_ci } 16931cb0ef41Sopenharmony_ci if (pair.high_gp() == old_reg) { 16941cb0ef41Sopenharmony_ci return LiftoffRegister::ForPair(pair.low_gp(), new_reg); 16951cb0ef41Sopenharmony_ci } 16961cb0ef41Sopenharmony_ci return pair; 16971cb0ef41Sopenharmony_ci} 16981cb0ef41Sopenharmony_ci 16991cb0ef41Sopenharmony_ciinline void Emit64BitShiftOperation( 17001cb0ef41Sopenharmony_ci LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister src, 17011cb0ef41Sopenharmony_ci Register amount, void (TurboAssembler::*emit_shift)(Register, Register)) { 17021cb0ef41Sopenharmony_ci // Temporary registers cannot overlap with {dst}. 17031cb0ef41Sopenharmony_ci LiftoffRegList pinned = {dst}; 17041cb0ef41Sopenharmony_ci 17051cb0ef41Sopenharmony_ci constexpr size_t kMaxRegMoves = 3; 17061cb0ef41Sopenharmony_ci base::SmallVector<LiftoffAssembler::ParallelRegisterMoveTuple, kMaxRegMoves> 17071cb0ef41Sopenharmony_ci reg_moves; 17081cb0ef41Sopenharmony_ci 17091cb0ef41Sopenharmony_ci // If {dst} contains {ecx}, replace it by an unused register, which is then 17101cb0ef41Sopenharmony_ci // moved to {ecx} in the end. 17111cb0ef41Sopenharmony_ci Register ecx_replace = no_reg; 17121cb0ef41Sopenharmony_ci if (PairContains(dst, ecx)) { 17131cb0ef41Sopenharmony_ci ecx_replace = assm->GetUnusedRegister(kGpReg, pinned).gp(); 17141cb0ef41Sopenharmony_ci dst = ReplaceInPair(dst, ecx, ecx_replace); 17151cb0ef41Sopenharmony_ci // If {amount} needs to be moved to {ecx}, but {ecx} is in use (and not part 17161cb0ef41Sopenharmony_ci // of {dst}, hence overwritten anyway), move {ecx} to a tmp register and 17171cb0ef41Sopenharmony_ci // restore it at the end. 17181cb0ef41Sopenharmony_ci } else if (amount != ecx && 17191cb0ef41Sopenharmony_ci (assm->cache_state()->is_used(LiftoffRegister(ecx)) || 17201cb0ef41Sopenharmony_ci pinned.has(LiftoffRegister(ecx)))) { 17211cb0ef41Sopenharmony_ci ecx_replace = assm->GetUnusedRegister(kGpReg, pinned).gp(); 17221cb0ef41Sopenharmony_ci reg_moves.emplace_back(ecx_replace, ecx, kI32); 17231cb0ef41Sopenharmony_ci } 17241cb0ef41Sopenharmony_ci 17251cb0ef41Sopenharmony_ci reg_moves.emplace_back(dst, src, kI64); 17261cb0ef41Sopenharmony_ci reg_moves.emplace_back(ecx, amount, kI32); 17271cb0ef41Sopenharmony_ci assm->ParallelRegisterMove(base::VectorOf(reg_moves)); 17281cb0ef41Sopenharmony_ci 17291cb0ef41Sopenharmony_ci // Do the actual shift. 17301cb0ef41Sopenharmony_ci (assm->*emit_shift)(dst.high_gp(), dst.low_gp()); 17311cb0ef41Sopenharmony_ci 17321cb0ef41Sopenharmony_ci // Restore {ecx} if needed. 17331cb0ef41Sopenharmony_ci if (ecx_replace != no_reg) assm->mov(ecx, ecx_replace); 17341cb0ef41Sopenharmony_ci} 17351cb0ef41Sopenharmony_ci} // namespace liftoff 17361cb0ef41Sopenharmony_ci 17371cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_shl(LiftoffRegister dst, LiftoffRegister src, 17381cb0ef41Sopenharmony_ci Register amount) { 17391cb0ef41Sopenharmony_ci liftoff::Emit64BitShiftOperation(this, dst, src, amount, 17401cb0ef41Sopenharmony_ci &TurboAssembler::ShlPair_cl); 17411cb0ef41Sopenharmony_ci} 17421cb0ef41Sopenharmony_ci 17431cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_shli(LiftoffRegister dst, LiftoffRegister src, 17441cb0ef41Sopenharmony_ci int32_t amount) { 17451cb0ef41Sopenharmony_ci amount &= 63; 17461cb0ef41Sopenharmony_ci if (amount >= 32) { 17471cb0ef41Sopenharmony_ci if (dst.high_gp() != src.low_gp()) mov(dst.high_gp(), src.low_gp()); 17481cb0ef41Sopenharmony_ci if (amount != 32) shl(dst.high_gp(), amount - 32); 17491cb0ef41Sopenharmony_ci xor_(dst.low_gp(), dst.low_gp()); 17501cb0ef41Sopenharmony_ci } else { 17511cb0ef41Sopenharmony_ci if (dst != src) Move(dst, src, kI64); 17521cb0ef41Sopenharmony_ci ShlPair(dst.high_gp(), dst.low_gp(), amount); 17531cb0ef41Sopenharmony_ci } 17541cb0ef41Sopenharmony_ci} 17551cb0ef41Sopenharmony_ci 17561cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_sar(LiftoffRegister dst, LiftoffRegister src, 17571cb0ef41Sopenharmony_ci Register amount) { 17581cb0ef41Sopenharmony_ci liftoff::Emit64BitShiftOperation(this, dst, src, amount, 17591cb0ef41Sopenharmony_ci &TurboAssembler::SarPair_cl); 17601cb0ef41Sopenharmony_ci} 17611cb0ef41Sopenharmony_ci 17621cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_sari(LiftoffRegister dst, LiftoffRegister src, 17631cb0ef41Sopenharmony_ci int32_t amount) { 17641cb0ef41Sopenharmony_ci amount &= 63; 17651cb0ef41Sopenharmony_ci if (amount >= 32) { 17661cb0ef41Sopenharmony_ci if (dst.low_gp() != src.high_gp()) mov(dst.low_gp(), src.high_gp()); 17671cb0ef41Sopenharmony_ci if (dst.high_gp() != src.high_gp()) mov(dst.high_gp(), src.high_gp()); 17681cb0ef41Sopenharmony_ci if (amount != 32) sar(dst.low_gp(), amount - 32); 17691cb0ef41Sopenharmony_ci sar(dst.high_gp(), 31); 17701cb0ef41Sopenharmony_ci } else { 17711cb0ef41Sopenharmony_ci if (dst != src) Move(dst, src, kI64); 17721cb0ef41Sopenharmony_ci SarPair(dst.high_gp(), dst.low_gp(), amount); 17731cb0ef41Sopenharmony_ci } 17741cb0ef41Sopenharmony_ci} 17751cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_shr(LiftoffRegister dst, LiftoffRegister src, 17761cb0ef41Sopenharmony_ci Register amount) { 17771cb0ef41Sopenharmony_ci liftoff::Emit64BitShiftOperation(this, dst, src, amount, 17781cb0ef41Sopenharmony_ci &TurboAssembler::ShrPair_cl); 17791cb0ef41Sopenharmony_ci} 17801cb0ef41Sopenharmony_ci 17811cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_shri(LiftoffRegister dst, LiftoffRegister src, 17821cb0ef41Sopenharmony_ci int32_t amount) { 17831cb0ef41Sopenharmony_ci amount &= 63; 17841cb0ef41Sopenharmony_ci if (amount >= 32) { 17851cb0ef41Sopenharmony_ci if (dst.low_gp() != src.high_gp()) mov(dst.low_gp(), src.high_gp()); 17861cb0ef41Sopenharmony_ci if (amount != 32) shr(dst.low_gp(), amount - 32); 17871cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); 17881cb0ef41Sopenharmony_ci } else { 17891cb0ef41Sopenharmony_ci if (dst != src) Move(dst, src, kI64); 17901cb0ef41Sopenharmony_ci ShrPair(dst.high_gp(), dst.low_gp(), amount); 17911cb0ef41Sopenharmony_ci } 17921cb0ef41Sopenharmony_ci} 17931cb0ef41Sopenharmony_ci 17941cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_clz(LiftoffRegister dst, LiftoffRegister src) { 17951cb0ef41Sopenharmony_ci // return high == 0 ? 32 + CLZ32(low) : CLZ32(high); 17961cb0ef41Sopenharmony_ci Label done; 17971cb0ef41Sopenharmony_ci Register safe_dst = dst.low_gp(); 17981cb0ef41Sopenharmony_ci if (src.low_gp() == safe_dst) safe_dst = dst.high_gp(); 17991cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(LZCNT)) { 18001cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, LZCNT); 18011cb0ef41Sopenharmony_ci lzcnt(safe_dst, src.high_gp()); // Sets CF if high == 0. 18021cb0ef41Sopenharmony_ci j(not_carry, &done, Label::kNear); 18031cb0ef41Sopenharmony_ci lzcnt(safe_dst, src.low_gp()); 18041cb0ef41Sopenharmony_ci add(safe_dst, Immediate(32)); // 32 + CLZ32(low) 18051cb0ef41Sopenharmony_ci } else { 18061cb0ef41Sopenharmony_ci // CLZ32(x) =^ x == 0 ? 32 : 31 - BSR32(x) 18071cb0ef41Sopenharmony_ci Label high_is_zero; 18081cb0ef41Sopenharmony_ci bsr(safe_dst, src.high_gp()); // Sets ZF is high == 0. 18091cb0ef41Sopenharmony_ci j(zero, &high_is_zero, Label::kNear); 18101cb0ef41Sopenharmony_ci xor_(safe_dst, Immediate(31)); // for x in [0..31], 31^x == 31-x. 18111cb0ef41Sopenharmony_ci jmp(&done, Label::kNear); 18121cb0ef41Sopenharmony_ci 18131cb0ef41Sopenharmony_ci bind(&high_is_zero); 18141cb0ef41Sopenharmony_ci Label low_not_zero; 18151cb0ef41Sopenharmony_ci bsr(safe_dst, src.low_gp()); 18161cb0ef41Sopenharmony_ci j(not_zero, &low_not_zero, Label::kNear); 18171cb0ef41Sopenharmony_ci mov(safe_dst, Immediate(64 ^ 63)); // 64, after the xor below. 18181cb0ef41Sopenharmony_ci bind(&low_not_zero); 18191cb0ef41Sopenharmony_ci xor_(safe_dst, 63); // for x in [0..31], 63^x == 63-x. 18201cb0ef41Sopenharmony_ci } 18211cb0ef41Sopenharmony_ci 18221cb0ef41Sopenharmony_ci bind(&done); 18231cb0ef41Sopenharmony_ci if (safe_dst != dst.low_gp()) mov(dst.low_gp(), safe_dst); 18241cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); // High word of result is always 0. 18251cb0ef41Sopenharmony_ci} 18261cb0ef41Sopenharmony_ci 18271cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src) { 18281cb0ef41Sopenharmony_ci // return low == 0 ? 32 + CTZ32(high) : CTZ32(low); 18291cb0ef41Sopenharmony_ci Label done; 18301cb0ef41Sopenharmony_ci Register safe_dst = dst.low_gp(); 18311cb0ef41Sopenharmony_ci if (src.high_gp() == safe_dst) safe_dst = dst.high_gp(); 18321cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(BMI1)) { 18331cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, BMI1); 18341cb0ef41Sopenharmony_ci tzcnt(safe_dst, src.low_gp()); // Sets CF if low == 0. 18351cb0ef41Sopenharmony_ci j(not_carry, &done, Label::kNear); 18361cb0ef41Sopenharmony_ci tzcnt(safe_dst, src.high_gp()); 18371cb0ef41Sopenharmony_ci add(safe_dst, Immediate(32)); // 32 + CTZ32(high) 18381cb0ef41Sopenharmony_ci } else { 18391cb0ef41Sopenharmony_ci // CTZ32(x) =^ x == 0 ? 32 : BSF32(x) 18401cb0ef41Sopenharmony_ci bsf(safe_dst, src.low_gp()); // Sets ZF is low == 0. 18411cb0ef41Sopenharmony_ci j(not_zero, &done, Label::kNear); 18421cb0ef41Sopenharmony_ci 18431cb0ef41Sopenharmony_ci Label high_not_zero; 18441cb0ef41Sopenharmony_ci bsf(safe_dst, src.high_gp()); 18451cb0ef41Sopenharmony_ci j(not_zero, &high_not_zero, Label::kNear); 18461cb0ef41Sopenharmony_ci mov(safe_dst, 64); // low == 0 and high == 0 18471cb0ef41Sopenharmony_ci jmp(&done); 18481cb0ef41Sopenharmony_ci bind(&high_not_zero); 18491cb0ef41Sopenharmony_ci add(safe_dst, Immediate(32)); // 32 + CTZ32(high) 18501cb0ef41Sopenharmony_ci } 18511cb0ef41Sopenharmony_ci 18521cb0ef41Sopenharmony_ci bind(&done); 18531cb0ef41Sopenharmony_ci if (safe_dst != dst.low_gp()) mov(dst.low_gp(), safe_dst); 18541cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); // High word of result is always 0. 18551cb0ef41Sopenharmony_ci} 18561cb0ef41Sopenharmony_ci 18571cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_i64_popcnt(LiftoffRegister dst, 18581cb0ef41Sopenharmony_ci LiftoffRegister src) { 18591cb0ef41Sopenharmony_ci if (!CpuFeatures::IsSupported(POPCNT)) return false; 18601cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, POPCNT); 18611cb0ef41Sopenharmony_ci // Produce partial popcnts in the two dst registers. 18621cb0ef41Sopenharmony_ci Register src1 = src.high_gp() == dst.low_gp() ? src.high_gp() : src.low_gp(); 18631cb0ef41Sopenharmony_ci Register src2 = src.high_gp() == dst.low_gp() ? src.low_gp() : src.high_gp(); 18641cb0ef41Sopenharmony_ci popcnt(dst.low_gp(), src1); 18651cb0ef41Sopenharmony_ci popcnt(dst.high_gp(), src2); 18661cb0ef41Sopenharmony_ci // Add the two into the lower dst reg, clear the higher dst reg. 18671cb0ef41Sopenharmony_ci add(dst.low_gp(), dst.high_gp()); 18681cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); 18691cb0ef41Sopenharmony_ci return true; 18701cb0ef41Sopenharmony_ci} 18711cb0ef41Sopenharmony_ci 18721cb0ef41Sopenharmony_civoid LiftoffAssembler::IncrementSmi(LiftoffRegister dst, int offset) { 18731cb0ef41Sopenharmony_ci add(Operand(dst.gp(), offset), Immediate(Smi::FromInt(1))); 18741cb0ef41Sopenharmony_ci} 18751cb0ef41Sopenharmony_ci 18761cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_add(DoubleRegister dst, DoubleRegister lhs, 18771cb0ef41Sopenharmony_ci DoubleRegister rhs) { 18781cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 18791cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 18801cb0ef41Sopenharmony_ci vaddss(dst, lhs, rhs); 18811cb0ef41Sopenharmony_ci } else if (dst == rhs) { 18821cb0ef41Sopenharmony_ci addss(dst, lhs); 18831cb0ef41Sopenharmony_ci } else { 18841cb0ef41Sopenharmony_ci if (dst != lhs) movss(dst, lhs); 18851cb0ef41Sopenharmony_ci addss(dst, rhs); 18861cb0ef41Sopenharmony_ci } 18871cb0ef41Sopenharmony_ci} 18881cb0ef41Sopenharmony_ci 18891cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_sub(DoubleRegister dst, DoubleRegister lhs, 18901cb0ef41Sopenharmony_ci DoubleRegister rhs) { 18911cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 18921cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 18931cb0ef41Sopenharmony_ci vsubss(dst, lhs, rhs); 18941cb0ef41Sopenharmony_ci } else if (dst == rhs) { 18951cb0ef41Sopenharmony_ci movss(liftoff::kScratchDoubleReg, rhs); 18961cb0ef41Sopenharmony_ci movss(dst, lhs); 18971cb0ef41Sopenharmony_ci subss(dst, liftoff::kScratchDoubleReg); 18981cb0ef41Sopenharmony_ci } else { 18991cb0ef41Sopenharmony_ci if (dst != lhs) movss(dst, lhs); 19001cb0ef41Sopenharmony_ci subss(dst, rhs); 19011cb0ef41Sopenharmony_ci } 19021cb0ef41Sopenharmony_ci} 19031cb0ef41Sopenharmony_ci 19041cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_mul(DoubleRegister dst, DoubleRegister lhs, 19051cb0ef41Sopenharmony_ci DoubleRegister rhs) { 19061cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 19071cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 19081cb0ef41Sopenharmony_ci vmulss(dst, lhs, rhs); 19091cb0ef41Sopenharmony_ci } else if (dst == rhs) { 19101cb0ef41Sopenharmony_ci mulss(dst, lhs); 19111cb0ef41Sopenharmony_ci } else { 19121cb0ef41Sopenharmony_ci if (dst != lhs) movss(dst, lhs); 19131cb0ef41Sopenharmony_ci mulss(dst, rhs); 19141cb0ef41Sopenharmony_ci } 19151cb0ef41Sopenharmony_ci} 19161cb0ef41Sopenharmony_ci 19171cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_div(DoubleRegister dst, DoubleRegister lhs, 19181cb0ef41Sopenharmony_ci DoubleRegister rhs) { 19191cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 19201cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 19211cb0ef41Sopenharmony_ci vdivss(dst, lhs, rhs); 19221cb0ef41Sopenharmony_ci } else if (dst == rhs) { 19231cb0ef41Sopenharmony_ci movss(liftoff::kScratchDoubleReg, rhs); 19241cb0ef41Sopenharmony_ci movss(dst, lhs); 19251cb0ef41Sopenharmony_ci divss(dst, liftoff::kScratchDoubleReg); 19261cb0ef41Sopenharmony_ci } else { 19271cb0ef41Sopenharmony_ci if (dst != lhs) movss(dst, lhs); 19281cb0ef41Sopenharmony_ci divss(dst, rhs); 19291cb0ef41Sopenharmony_ci } 19301cb0ef41Sopenharmony_ci} 19311cb0ef41Sopenharmony_ci 19321cb0ef41Sopenharmony_cinamespace liftoff { 19331cb0ef41Sopenharmony_cienum class MinOrMax : uint8_t { kMin, kMax }; 19341cb0ef41Sopenharmony_citemplate <typename type> 19351cb0ef41Sopenharmony_ciinline void EmitFloatMinOrMax(LiftoffAssembler* assm, DoubleRegister dst, 19361cb0ef41Sopenharmony_ci DoubleRegister lhs, DoubleRegister rhs, 19371cb0ef41Sopenharmony_ci MinOrMax min_or_max) { 19381cb0ef41Sopenharmony_ci Label is_nan; 19391cb0ef41Sopenharmony_ci Label lhs_below_rhs; 19401cb0ef41Sopenharmony_ci Label lhs_above_rhs; 19411cb0ef41Sopenharmony_ci Label done; 19421cb0ef41Sopenharmony_ci 19431cb0ef41Sopenharmony_ci // We need one tmp register to extract the sign bit. Get it right at the 19441cb0ef41Sopenharmony_ci // beginning, such that the spilling code is not accidentially jumped over. 19451cb0ef41Sopenharmony_ci Register tmp = assm->GetUnusedRegister(kGpReg, {}).gp(); 19461cb0ef41Sopenharmony_ci 19471cb0ef41Sopenharmony_ci#define dop(name, ...) \ 19481cb0ef41Sopenharmony_ci do { \ 19491cb0ef41Sopenharmony_ci if (sizeof(type) == 4) { \ 19501cb0ef41Sopenharmony_ci assm->name##s(__VA_ARGS__); \ 19511cb0ef41Sopenharmony_ci } else { \ 19521cb0ef41Sopenharmony_ci assm->name##d(__VA_ARGS__); \ 19531cb0ef41Sopenharmony_ci } \ 19541cb0ef41Sopenharmony_ci } while (false) 19551cb0ef41Sopenharmony_ci 19561cb0ef41Sopenharmony_ci // Check the easy cases first: nan (e.g. unordered), smaller and greater. 19571cb0ef41Sopenharmony_ci // NaN has to be checked first, because PF=1 implies CF=1. 19581cb0ef41Sopenharmony_ci dop(ucomis, lhs, rhs); 19591cb0ef41Sopenharmony_ci assm->j(parity_even, &is_nan, Label::kNear); // PF=1 19601cb0ef41Sopenharmony_ci assm->j(below, &lhs_below_rhs, Label::kNear); // CF=1 19611cb0ef41Sopenharmony_ci assm->j(above, &lhs_above_rhs, Label::kNear); // CF=0 && ZF=0 19621cb0ef41Sopenharmony_ci 19631cb0ef41Sopenharmony_ci // If we get here, then either 19641cb0ef41Sopenharmony_ci // a) {lhs == rhs}, 19651cb0ef41Sopenharmony_ci // b) {lhs == -0.0} and {rhs == 0.0}, or 19661cb0ef41Sopenharmony_ci // c) {lhs == 0.0} and {rhs == -0.0}. 19671cb0ef41Sopenharmony_ci // For a), it does not matter whether we return {lhs} or {rhs}. Check the sign 19681cb0ef41Sopenharmony_ci // bit of {rhs} to differentiate b) and c). 19691cb0ef41Sopenharmony_ci dop(movmskp, tmp, rhs); 19701cb0ef41Sopenharmony_ci assm->test(tmp, Immediate(1)); 19711cb0ef41Sopenharmony_ci assm->j(zero, &lhs_below_rhs, Label::kNear); 19721cb0ef41Sopenharmony_ci assm->jmp(&lhs_above_rhs, Label::kNear); 19731cb0ef41Sopenharmony_ci 19741cb0ef41Sopenharmony_ci assm->bind(&is_nan); 19751cb0ef41Sopenharmony_ci // Create a NaN output. 19761cb0ef41Sopenharmony_ci dop(xorp, dst, dst); 19771cb0ef41Sopenharmony_ci dop(divs, dst, dst); 19781cb0ef41Sopenharmony_ci assm->jmp(&done, Label::kNear); 19791cb0ef41Sopenharmony_ci 19801cb0ef41Sopenharmony_ci assm->bind(&lhs_below_rhs); 19811cb0ef41Sopenharmony_ci DoubleRegister lhs_below_rhs_src = min_or_max == MinOrMax::kMin ? lhs : rhs; 19821cb0ef41Sopenharmony_ci if (dst != lhs_below_rhs_src) dop(movs, dst, lhs_below_rhs_src); 19831cb0ef41Sopenharmony_ci assm->jmp(&done, Label::kNear); 19841cb0ef41Sopenharmony_ci 19851cb0ef41Sopenharmony_ci assm->bind(&lhs_above_rhs); 19861cb0ef41Sopenharmony_ci DoubleRegister lhs_above_rhs_src = min_or_max == MinOrMax::kMin ? rhs : lhs; 19871cb0ef41Sopenharmony_ci if (dst != lhs_above_rhs_src) dop(movs, dst, lhs_above_rhs_src); 19881cb0ef41Sopenharmony_ci 19891cb0ef41Sopenharmony_ci assm->bind(&done); 19901cb0ef41Sopenharmony_ci} 19911cb0ef41Sopenharmony_ci} // namespace liftoff 19921cb0ef41Sopenharmony_ci 19931cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs, 19941cb0ef41Sopenharmony_ci DoubleRegister rhs) { 19951cb0ef41Sopenharmony_ci liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs, 19961cb0ef41Sopenharmony_ci liftoff::MinOrMax::kMin); 19971cb0ef41Sopenharmony_ci} 19981cb0ef41Sopenharmony_ci 19991cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs, 20001cb0ef41Sopenharmony_ci DoubleRegister rhs) { 20011cb0ef41Sopenharmony_ci liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs, 20021cb0ef41Sopenharmony_ci liftoff::MinOrMax::kMax); 20031cb0ef41Sopenharmony_ci} 20041cb0ef41Sopenharmony_ci 20051cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs, 20061cb0ef41Sopenharmony_ci DoubleRegister rhs) { 20071cb0ef41Sopenharmony_ci static constexpr int kF32SignBit = 1 << 31; 20081cb0ef41Sopenharmony_ci LiftoffRegList pinned; 20091cb0ef41Sopenharmony_ci Register scratch = pinned.set(GetUnusedRegister(kGpReg, pinned)).gp(); 20101cb0ef41Sopenharmony_ci Register scratch2 = GetUnusedRegister(kGpReg, pinned).gp(); 20111cb0ef41Sopenharmony_ci Movd(scratch, lhs); // move {lhs} into {scratch}. 20121cb0ef41Sopenharmony_ci and_(scratch, Immediate(~kF32SignBit)); // clear sign bit in {scratch}. 20131cb0ef41Sopenharmony_ci Movd(scratch2, rhs); // move {rhs} into {scratch2}. 20141cb0ef41Sopenharmony_ci and_(scratch2, Immediate(kF32SignBit)); // isolate sign bit in {scratch2}. 20151cb0ef41Sopenharmony_ci or_(scratch, scratch2); // combine {scratch2} into {scratch}. 20161cb0ef41Sopenharmony_ci Movd(dst, scratch); // move result into {dst}. 20171cb0ef41Sopenharmony_ci} 20181cb0ef41Sopenharmony_ci 20191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) { 20201cb0ef41Sopenharmony_ci static constexpr uint32_t kSignBit = uint32_t{1} << 31; 20211cb0ef41Sopenharmony_ci if (dst == src) { 20221cb0ef41Sopenharmony_ci TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit - 1); 20231cb0ef41Sopenharmony_ci Andps(dst, liftoff::kScratchDoubleReg); 20241cb0ef41Sopenharmony_ci } else { 20251cb0ef41Sopenharmony_ci TurboAssembler::Move(dst, kSignBit - 1); 20261cb0ef41Sopenharmony_ci Andps(dst, src); 20271cb0ef41Sopenharmony_ci } 20281cb0ef41Sopenharmony_ci} 20291cb0ef41Sopenharmony_ci 20301cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_neg(DoubleRegister dst, DoubleRegister src) { 20311cb0ef41Sopenharmony_ci static constexpr uint32_t kSignBit = uint32_t{1} << 31; 20321cb0ef41Sopenharmony_ci if (dst == src) { 20331cb0ef41Sopenharmony_ci TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit); 20341cb0ef41Sopenharmony_ci Xorps(dst, liftoff::kScratchDoubleReg); 20351cb0ef41Sopenharmony_ci } else { 20361cb0ef41Sopenharmony_ci TurboAssembler::Move(dst, kSignBit); 20371cb0ef41Sopenharmony_ci Xorps(dst, src); 20381cb0ef41Sopenharmony_ci } 20391cb0ef41Sopenharmony_ci} 20401cb0ef41Sopenharmony_ci 20411cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32_ceil(DoubleRegister dst, DoubleRegister src) { 20421cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 20431cb0ef41Sopenharmony_ci roundss(dst, src, kRoundUp); 20441cb0ef41Sopenharmony_ci return true; 20451cb0ef41Sopenharmony_ci} 20461cb0ef41Sopenharmony_ci 20471cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32_floor(DoubleRegister dst, DoubleRegister src) { 20481cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 20491cb0ef41Sopenharmony_ci roundss(dst, src, kRoundDown); 20501cb0ef41Sopenharmony_ci return true; 20511cb0ef41Sopenharmony_ci} 20521cb0ef41Sopenharmony_ci 20531cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32_trunc(DoubleRegister dst, DoubleRegister src) { 20541cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 20551cb0ef41Sopenharmony_ci roundss(dst, src, kRoundToZero); 20561cb0ef41Sopenharmony_ci return true; 20571cb0ef41Sopenharmony_ci} 20581cb0ef41Sopenharmony_ci 20591cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32_nearest_int(DoubleRegister dst, 20601cb0ef41Sopenharmony_ci DoubleRegister src) { 20611cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 20621cb0ef41Sopenharmony_ci roundss(dst, src, kRoundToNearest); 20631cb0ef41Sopenharmony_ci return true; 20641cb0ef41Sopenharmony_ci} 20651cb0ef41Sopenharmony_ci 20661cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_sqrt(DoubleRegister dst, DoubleRegister src) { 20671cb0ef41Sopenharmony_ci Sqrtss(dst, src); 20681cb0ef41Sopenharmony_ci} 20691cb0ef41Sopenharmony_ci 20701cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_add(DoubleRegister dst, DoubleRegister lhs, 20711cb0ef41Sopenharmony_ci DoubleRegister rhs) { 20721cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 20731cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 20741cb0ef41Sopenharmony_ci vaddsd(dst, lhs, rhs); 20751cb0ef41Sopenharmony_ci } else if (dst == rhs) { 20761cb0ef41Sopenharmony_ci addsd(dst, lhs); 20771cb0ef41Sopenharmony_ci } else { 20781cb0ef41Sopenharmony_ci if (dst != lhs) movsd(dst, lhs); 20791cb0ef41Sopenharmony_ci addsd(dst, rhs); 20801cb0ef41Sopenharmony_ci } 20811cb0ef41Sopenharmony_ci} 20821cb0ef41Sopenharmony_ci 20831cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_sub(DoubleRegister dst, DoubleRegister lhs, 20841cb0ef41Sopenharmony_ci DoubleRegister rhs) { 20851cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 20861cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 20871cb0ef41Sopenharmony_ci vsubsd(dst, lhs, rhs); 20881cb0ef41Sopenharmony_ci } else if (dst == rhs) { 20891cb0ef41Sopenharmony_ci movsd(liftoff::kScratchDoubleReg, rhs); 20901cb0ef41Sopenharmony_ci movsd(dst, lhs); 20911cb0ef41Sopenharmony_ci subsd(dst, liftoff::kScratchDoubleReg); 20921cb0ef41Sopenharmony_ci } else { 20931cb0ef41Sopenharmony_ci if (dst != lhs) movsd(dst, lhs); 20941cb0ef41Sopenharmony_ci subsd(dst, rhs); 20951cb0ef41Sopenharmony_ci } 20961cb0ef41Sopenharmony_ci} 20971cb0ef41Sopenharmony_ci 20981cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_mul(DoubleRegister dst, DoubleRegister lhs, 20991cb0ef41Sopenharmony_ci DoubleRegister rhs) { 21001cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 21011cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 21021cb0ef41Sopenharmony_ci vmulsd(dst, lhs, rhs); 21031cb0ef41Sopenharmony_ci } else if (dst == rhs) { 21041cb0ef41Sopenharmony_ci mulsd(dst, lhs); 21051cb0ef41Sopenharmony_ci } else { 21061cb0ef41Sopenharmony_ci if (dst != lhs) movsd(dst, lhs); 21071cb0ef41Sopenharmony_ci mulsd(dst, rhs); 21081cb0ef41Sopenharmony_ci } 21091cb0ef41Sopenharmony_ci} 21101cb0ef41Sopenharmony_ci 21111cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_div(DoubleRegister dst, DoubleRegister lhs, 21121cb0ef41Sopenharmony_ci DoubleRegister rhs) { 21131cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 21141cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 21151cb0ef41Sopenharmony_ci vdivsd(dst, lhs, rhs); 21161cb0ef41Sopenharmony_ci } else if (dst == rhs) { 21171cb0ef41Sopenharmony_ci movsd(liftoff::kScratchDoubleReg, rhs); 21181cb0ef41Sopenharmony_ci movsd(dst, lhs); 21191cb0ef41Sopenharmony_ci divsd(dst, liftoff::kScratchDoubleReg); 21201cb0ef41Sopenharmony_ci } else { 21211cb0ef41Sopenharmony_ci if (dst != lhs) movsd(dst, lhs); 21221cb0ef41Sopenharmony_ci divsd(dst, rhs); 21231cb0ef41Sopenharmony_ci } 21241cb0ef41Sopenharmony_ci} 21251cb0ef41Sopenharmony_ci 21261cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs, 21271cb0ef41Sopenharmony_ci DoubleRegister rhs) { 21281cb0ef41Sopenharmony_ci liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs, 21291cb0ef41Sopenharmony_ci liftoff::MinOrMax::kMin); 21301cb0ef41Sopenharmony_ci} 21311cb0ef41Sopenharmony_ci 21321cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs, 21331cb0ef41Sopenharmony_ci DoubleRegister rhs) { 21341cb0ef41Sopenharmony_ci static constexpr int kF32SignBit = 1 << 31; 21351cb0ef41Sopenharmony_ci // On ia32, we cannot hold the whole f64 value in a gp register, so we just 21361cb0ef41Sopenharmony_ci // operate on the upper half (UH). 21371cb0ef41Sopenharmony_ci LiftoffRegList pinned; 21381cb0ef41Sopenharmony_ci Register scratch = pinned.set(GetUnusedRegister(kGpReg, pinned)).gp(); 21391cb0ef41Sopenharmony_ci Register scratch2 = GetUnusedRegister(kGpReg, pinned).gp(); 21401cb0ef41Sopenharmony_ci 21411cb0ef41Sopenharmony_ci Pextrd(scratch, lhs, 1); // move UH of {lhs} into {scratch}. 21421cb0ef41Sopenharmony_ci and_(scratch, Immediate(~kF32SignBit)); // clear sign bit in {scratch}. 21431cb0ef41Sopenharmony_ci Pextrd(scratch2, rhs, 1); // move UH of {rhs} into {scratch2}. 21441cb0ef41Sopenharmony_ci and_(scratch2, Immediate(kF32SignBit)); // isolate sign bit in {scratch2}. 21451cb0ef41Sopenharmony_ci or_(scratch, scratch2); // combine {scratch2} into {scratch}. 21461cb0ef41Sopenharmony_ci movsd(dst, lhs); // move {lhs} into {dst}. 21471cb0ef41Sopenharmony_ci Pinsrd(dst, scratch, 1); // insert {scratch} into UH of {dst}. 21481cb0ef41Sopenharmony_ci} 21491cb0ef41Sopenharmony_ci 21501cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs, 21511cb0ef41Sopenharmony_ci DoubleRegister rhs) { 21521cb0ef41Sopenharmony_ci liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs, 21531cb0ef41Sopenharmony_ci liftoff::MinOrMax::kMax); 21541cb0ef41Sopenharmony_ci} 21551cb0ef41Sopenharmony_ci 21561cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_abs(DoubleRegister dst, DoubleRegister src) { 21571cb0ef41Sopenharmony_ci static constexpr uint64_t kSignBit = uint64_t{1} << 63; 21581cb0ef41Sopenharmony_ci if (dst == src) { 21591cb0ef41Sopenharmony_ci TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit - 1); 21601cb0ef41Sopenharmony_ci Andpd(dst, liftoff::kScratchDoubleReg); 21611cb0ef41Sopenharmony_ci } else { 21621cb0ef41Sopenharmony_ci TurboAssembler::Move(dst, kSignBit - 1); 21631cb0ef41Sopenharmony_ci Andpd(dst, src); 21641cb0ef41Sopenharmony_ci } 21651cb0ef41Sopenharmony_ci} 21661cb0ef41Sopenharmony_ci 21671cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_neg(DoubleRegister dst, DoubleRegister src) { 21681cb0ef41Sopenharmony_ci static constexpr uint64_t kSignBit = uint64_t{1} << 63; 21691cb0ef41Sopenharmony_ci if (dst == src) { 21701cb0ef41Sopenharmony_ci TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit); 21711cb0ef41Sopenharmony_ci Xorpd(dst, liftoff::kScratchDoubleReg); 21721cb0ef41Sopenharmony_ci } else { 21731cb0ef41Sopenharmony_ci TurboAssembler::Move(dst, kSignBit); 21741cb0ef41Sopenharmony_ci Xorpd(dst, src); 21751cb0ef41Sopenharmony_ci } 21761cb0ef41Sopenharmony_ci} 21771cb0ef41Sopenharmony_ci 21781cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64_ceil(DoubleRegister dst, DoubleRegister src) { 21791cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 21801cb0ef41Sopenharmony_ci roundsd(dst, src, kRoundUp); 21811cb0ef41Sopenharmony_ci return true; 21821cb0ef41Sopenharmony_ci} 21831cb0ef41Sopenharmony_ci 21841cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64_floor(DoubleRegister dst, DoubleRegister src) { 21851cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 21861cb0ef41Sopenharmony_ci roundsd(dst, src, kRoundDown); 21871cb0ef41Sopenharmony_ci return true; 21881cb0ef41Sopenharmony_ci} 21891cb0ef41Sopenharmony_ci 21901cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64_trunc(DoubleRegister dst, DoubleRegister src) { 21911cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 21921cb0ef41Sopenharmony_ci roundsd(dst, src, kRoundToZero); 21931cb0ef41Sopenharmony_ci return true; 21941cb0ef41Sopenharmony_ci} 21951cb0ef41Sopenharmony_ci 21961cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64_nearest_int(DoubleRegister dst, 21971cb0ef41Sopenharmony_ci DoubleRegister src) { 21981cb0ef41Sopenharmony_ci RETURN_FALSE_IF_MISSING_CPU_FEATURE(SSE4_1); 21991cb0ef41Sopenharmony_ci roundsd(dst, src, kRoundToNearest); 22001cb0ef41Sopenharmony_ci return true; 22011cb0ef41Sopenharmony_ci} 22021cb0ef41Sopenharmony_ci 22031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_sqrt(DoubleRegister dst, DoubleRegister src) { 22041cb0ef41Sopenharmony_ci Sqrtsd(dst, src); 22051cb0ef41Sopenharmony_ci} 22061cb0ef41Sopenharmony_ci 22071cb0ef41Sopenharmony_cinamespace liftoff { 22081cb0ef41Sopenharmony_ci#define __ assm-> 22091cb0ef41Sopenharmony_ci// Used for float to int conversions. If the value in {converted_back} equals 22101cb0ef41Sopenharmony_ci// {src} afterwards, the conversion succeeded. 22111cb0ef41Sopenharmony_citemplate <typename dst_type, typename src_type> 22121cb0ef41Sopenharmony_ciinline void ConvertFloatToIntAndBack(LiftoffAssembler* assm, Register dst, 22131cb0ef41Sopenharmony_ci DoubleRegister src, 22141cb0ef41Sopenharmony_ci DoubleRegister converted_back, 22151cb0ef41Sopenharmony_ci LiftoffRegList pinned) { 22161cb0ef41Sopenharmony_ci if (std::is_same<double, src_type>::value) { // f64 22171cb0ef41Sopenharmony_ci if (std::is_signed<dst_type>::value) { // f64 -> i32 22181cb0ef41Sopenharmony_ci __ cvttsd2si(dst, src); 22191cb0ef41Sopenharmony_ci __ Cvtsi2sd(converted_back, dst); 22201cb0ef41Sopenharmony_ci } else { // f64 -> u32 22211cb0ef41Sopenharmony_ci __ Cvttsd2ui(dst, src, liftoff::kScratchDoubleReg); 22221cb0ef41Sopenharmony_ci __ Cvtui2sd(converted_back, dst, 22231cb0ef41Sopenharmony_ci __ GetUnusedRegister(kGpReg, pinned).gp()); 22241cb0ef41Sopenharmony_ci } 22251cb0ef41Sopenharmony_ci } else { // f32 22261cb0ef41Sopenharmony_ci if (std::is_signed<dst_type>::value) { // f32 -> i32 22271cb0ef41Sopenharmony_ci __ cvttss2si(dst, src); 22281cb0ef41Sopenharmony_ci __ Cvtsi2ss(converted_back, dst); 22291cb0ef41Sopenharmony_ci } else { // f32 -> u32 22301cb0ef41Sopenharmony_ci __ Cvttss2ui(dst, src, liftoff::kScratchDoubleReg); 22311cb0ef41Sopenharmony_ci __ Cvtui2ss(converted_back, dst, 22321cb0ef41Sopenharmony_ci __ GetUnusedRegister(kGpReg, pinned).gp()); 22331cb0ef41Sopenharmony_ci } 22341cb0ef41Sopenharmony_ci } 22351cb0ef41Sopenharmony_ci} 22361cb0ef41Sopenharmony_ci 22371cb0ef41Sopenharmony_citemplate <typename dst_type, typename src_type> 22381cb0ef41Sopenharmony_ciinline bool EmitTruncateFloatToInt(LiftoffAssembler* assm, Register dst, 22391cb0ef41Sopenharmony_ci DoubleRegister src, Label* trap) { 22401cb0ef41Sopenharmony_ci if (!CpuFeatures::IsSupported(SSE4_1)) { 22411cb0ef41Sopenharmony_ci __ bailout(kMissingCPUFeature, "no SSE4.1"); 22421cb0ef41Sopenharmony_ci return true; 22431cb0ef41Sopenharmony_ci } 22441cb0ef41Sopenharmony_ci CpuFeatureScope feature(assm, SSE4_1); 22451cb0ef41Sopenharmony_ci 22461cb0ef41Sopenharmony_ci LiftoffRegList pinned = {src, dst}; 22471cb0ef41Sopenharmony_ci DoubleRegister rounded = 22481cb0ef41Sopenharmony_ci pinned.set(__ GetUnusedRegister(kFpReg, pinned)).fp(); 22491cb0ef41Sopenharmony_ci DoubleRegister converted_back = 22501cb0ef41Sopenharmony_ci pinned.set(__ GetUnusedRegister(kFpReg, pinned)).fp(); 22511cb0ef41Sopenharmony_ci 22521cb0ef41Sopenharmony_ci if (std::is_same<double, src_type>::value) { // f64 22531cb0ef41Sopenharmony_ci __ roundsd(rounded, src, kRoundToZero); 22541cb0ef41Sopenharmony_ci } else { // f32 22551cb0ef41Sopenharmony_ci __ roundss(rounded, src, kRoundToZero); 22561cb0ef41Sopenharmony_ci } 22571cb0ef41Sopenharmony_ci ConvertFloatToIntAndBack<dst_type, src_type>(assm, dst, rounded, 22581cb0ef41Sopenharmony_ci converted_back, pinned); 22591cb0ef41Sopenharmony_ci if (std::is_same<double, src_type>::value) { // f64 22601cb0ef41Sopenharmony_ci __ ucomisd(converted_back, rounded); 22611cb0ef41Sopenharmony_ci } else { // f32 22621cb0ef41Sopenharmony_ci __ ucomiss(converted_back, rounded); 22631cb0ef41Sopenharmony_ci } 22641cb0ef41Sopenharmony_ci 22651cb0ef41Sopenharmony_ci // Jump to trap if PF is 0 (one of the operands was NaN) or they are not 22661cb0ef41Sopenharmony_ci // equal. 22671cb0ef41Sopenharmony_ci __ j(parity_even, trap); 22681cb0ef41Sopenharmony_ci __ j(not_equal, trap); 22691cb0ef41Sopenharmony_ci return true; 22701cb0ef41Sopenharmony_ci} 22711cb0ef41Sopenharmony_ci 22721cb0ef41Sopenharmony_citemplate <typename dst_type, typename src_type> 22731cb0ef41Sopenharmony_ciinline bool EmitSatTruncateFloatToInt(LiftoffAssembler* assm, Register dst, 22741cb0ef41Sopenharmony_ci DoubleRegister src) { 22751cb0ef41Sopenharmony_ci if (!CpuFeatures::IsSupported(SSE4_1)) { 22761cb0ef41Sopenharmony_ci __ bailout(kMissingCPUFeature, "no SSE4.1"); 22771cb0ef41Sopenharmony_ci return true; 22781cb0ef41Sopenharmony_ci } 22791cb0ef41Sopenharmony_ci CpuFeatureScope feature(assm, SSE4_1); 22801cb0ef41Sopenharmony_ci 22811cb0ef41Sopenharmony_ci Label done; 22821cb0ef41Sopenharmony_ci Label not_nan; 22831cb0ef41Sopenharmony_ci Label src_positive; 22841cb0ef41Sopenharmony_ci 22851cb0ef41Sopenharmony_ci LiftoffRegList pinned = {src, dst}; 22861cb0ef41Sopenharmony_ci DoubleRegister rounded = 22871cb0ef41Sopenharmony_ci pinned.set(__ GetUnusedRegister(kFpReg, pinned)).fp(); 22881cb0ef41Sopenharmony_ci DoubleRegister converted_back = 22891cb0ef41Sopenharmony_ci pinned.set(__ GetUnusedRegister(kFpReg, pinned)).fp(); 22901cb0ef41Sopenharmony_ci DoubleRegister zero_reg = 22911cb0ef41Sopenharmony_ci pinned.set(__ GetUnusedRegister(kFpReg, pinned)).fp(); 22921cb0ef41Sopenharmony_ci 22931cb0ef41Sopenharmony_ci if (std::is_same<double, src_type>::value) { // f64 22941cb0ef41Sopenharmony_ci __ roundsd(rounded, src, kRoundToZero); 22951cb0ef41Sopenharmony_ci } else { // f32 22961cb0ef41Sopenharmony_ci __ roundss(rounded, src, kRoundToZero); 22971cb0ef41Sopenharmony_ci } 22981cb0ef41Sopenharmony_ci 22991cb0ef41Sopenharmony_ci ConvertFloatToIntAndBack<dst_type, src_type>(assm, dst, rounded, 23001cb0ef41Sopenharmony_ci converted_back, pinned); 23011cb0ef41Sopenharmony_ci if (std::is_same<double, src_type>::value) { // f64 23021cb0ef41Sopenharmony_ci __ ucomisd(converted_back, rounded); 23031cb0ef41Sopenharmony_ci } else { // f32 23041cb0ef41Sopenharmony_ci __ ucomiss(converted_back, rounded); 23051cb0ef41Sopenharmony_ci } 23061cb0ef41Sopenharmony_ci 23071cb0ef41Sopenharmony_ci // Return 0 if PF is 0 (one of the operands was NaN) 23081cb0ef41Sopenharmony_ci __ j(parity_odd, ¬_nan); 23091cb0ef41Sopenharmony_ci __ xor_(dst, dst); 23101cb0ef41Sopenharmony_ci __ jmp(&done); 23111cb0ef41Sopenharmony_ci 23121cb0ef41Sopenharmony_ci __ bind(¬_nan); 23131cb0ef41Sopenharmony_ci // If rounding is as expected, return result 23141cb0ef41Sopenharmony_ci __ j(equal, &done); 23151cb0ef41Sopenharmony_ci 23161cb0ef41Sopenharmony_ci __ Xorpd(zero_reg, zero_reg); 23171cb0ef41Sopenharmony_ci 23181cb0ef41Sopenharmony_ci // if out-of-bounds, check if src is positive 23191cb0ef41Sopenharmony_ci if (std::is_same<double, src_type>::value) { // f64 23201cb0ef41Sopenharmony_ci __ ucomisd(src, zero_reg); 23211cb0ef41Sopenharmony_ci } else { // f32 23221cb0ef41Sopenharmony_ci __ ucomiss(src, zero_reg); 23231cb0ef41Sopenharmony_ci } 23241cb0ef41Sopenharmony_ci __ j(above, &src_positive); 23251cb0ef41Sopenharmony_ci __ mov(dst, Immediate(std::numeric_limits<dst_type>::min())); 23261cb0ef41Sopenharmony_ci __ jmp(&done); 23271cb0ef41Sopenharmony_ci 23281cb0ef41Sopenharmony_ci __ bind(&src_positive); 23291cb0ef41Sopenharmony_ci 23301cb0ef41Sopenharmony_ci __ mov(dst, Immediate(std::numeric_limits<dst_type>::max())); 23311cb0ef41Sopenharmony_ci 23321cb0ef41Sopenharmony_ci __ bind(&done); 23331cb0ef41Sopenharmony_ci return true; 23341cb0ef41Sopenharmony_ci} 23351cb0ef41Sopenharmony_ci#undef __ 23361cb0ef41Sopenharmony_ci} // namespace liftoff 23371cb0ef41Sopenharmony_ci 23381cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, 23391cb0ef41Sopenharmony_ci LiftoffRegister dst, 23401cb0ef41Sopenharmony_ci LiftoffRegister src, Label* trap) { 23411cb0ef41Sopenharmony_ci switch (opcode) { 23421cb0ef41Sopenharmony_ci case kExprI32ConvertI64: 23431cb0ef41Sopenharmony_ci if (dst.gp() != src.low_gp()) mov(dst.gp(), src.low_gp()); 23441cb0ef41Sopenharmony_ci return true; 23451cb0ef41Sopenharmony_ci case kExprI32SConvertF32: 23461cb0ef41Sopenharmony_ci return liftoff::EmitTruncateFloatToInt<int32_t, float>(this, dst.gp(), 23471cb0ef41Sopenharmony_ci src.fp(), trap); 23481cb0ef41Sopenharmony_ci case kExprI32UConvertF32: 23491cb0ef41Sopenharmony_ci return liftoff::EmitTruncateFloatToInt<uint32_t, float>(this, dst.gp(), 23501cb0ef41Sopenharmony_ci src.fp(), trap); 23511cb0ef41Sopenharmony_ci case kExprI32SConvertF64: 23521cb0ef41Sopenharmony_ci return liftoff::EmitTruncateFloatToInt<int32_t, double>(this, dst.gp(), 23531cb0ef41Sopenharmony_ci src.fp(), trap); 23541cb0ef41Sopenharmony_ci case kExprI32UConvertF64: 23551cb0ef41Sopenharmony_ci return liftoff::EmitTruncateFloatToInt<uint32_t, double>(this, dst.gp(), 23561cb0ef41Sopenharmony_ci src.fp(), trap); 23571cb0ef41Sopenharmony_ci case kExprI32SConvertSatF32: 23581cb0ef41Sopenharmony_ci return liftoff::EmitSatTruncateFloatToInt<int32_t, float>(this, dst.gp(), 23591cb0ef41Sopenharmony_ci src.fp()); 23601cb0ef41Sopenharmony_ci case kExprI32UConvertSatF32: 23611cb0ef41Sopenharmony_ci return liftoff::EmitSatTruncateFloatToInt<uint32_t, float>(this, dst.gp(), 23621cb0ef41Sopenharmony_ci src.fp()); 23631cb0ef41Sopenharmony_ci case kExprI32SConvertSatF64: 23641cb0ef41Sopenharmony_ci return liftoff::EmitSatTruncateFloatToInt<int32_t, double>(this, dst.gp(), 23651cb0ef41Sopenharmony_ci src.fp()); 23661cb0ef41Sopenharmony_ci case kExprI32UConvertSatF64: 23671cb0ef41Sopenharmony_ci return liftoff::EmitSatTruncateFloatToInt<uint32_t, double>( 23681cb0ef41Sopenharmony_ci this, dst.gp(), src.fp()); 23691cb0ef41Sopenharmony_ci case kExprI32ReinterpretF32: 23701cb0ef41Sopenharmony_ci Movd(dst.gp(), src.fp()); 23711cb0ef41Sopenharmony_ci return true; 23721cb0ef41Sopenharmony_ci case kExprI64SConvertI32: 23731cb0ef41Sopenharmony_ci if (dst.low_gp() != src.gp()) mov(dst.low_gp(), src.gp()); 23741cb0ef41Sopenharmony_ci if (dst.high_gp() != src.gp()) mov(dst.high_gp(), src.gp()); 23751cb0ef41Sopenharmony_ci sar(dst.high_gp(), 31); 23761cb0ef41Sopenharmony_ci return true; 23771cb0ef41Sopenharmony_ci case kExprI64UConvertI32: 23781cb0ef41Sopenharmony_ci if (dst.low_gp() != src.gp()) mov(dst.low_gp(), src.gp()); 23791cb0ef41Sopenharmony_ci xor_(dst.high_gp(), dst.high_gp()); 23801cb0ef41Sopenharmony_ci return true; 23811cb0ef41Sopenharmony_ci case kExprI64ReinterpretF64: 23821cb0ef41Sopenharmony_ci // Push src to the stack. 23831cb0ef41Sopenharmony_ci AllocateStackSpace(8); 23841cb0ef41Sopenharmony_ci movsd(Operand(esp, 0), src.fp()); 23851cb0ef41Sopenharmony_ci // Pop to dst. 23861cb0ef41Sopenharmony_ci pop(dst.low_gp()); 23871cb0ef41Sopenharmony_ci pop(dst.high_gp()); 23881cb0ef41Sopenharmony_ci return true; 23891cb0ef41Sopenharmony_ci case kExprF32SConvertI32: 23901cb0ef41Sopenharmony_ci cvtsi2ss(dst.fp(), src.gp()); 23911cb0ef41Sopenharmony_ci return true; 23921cb0ef41Sopenharmony_ci case kExprF32UConvertI32: { 23931cb0ef41Sopenharmony_ci LiftoffRegList pinned = {dst, src}; 23941cb0ef41Sopenharmony_ci Register scratch = GetUnusedRegister(kGpReg, pinned).gp(); 23951cb0ef41Sopenharmony_ci Cvtui2ss(dst.fp(), src.gp(), scratch); 23961cb0ef41Sopenharmony_ci return true; 23971cb0ef41Sopenharmony_ci } 23981cb0ef41Sopenharmony_ci case kExprF32ConvertF64: 23991cb0ef41Sopenharmony_ci cvtsd2ss(dst.fp(), src.fp()); 24001cb0ef41Sopenharmony_ci return true; 24011cb0ef41Sopenharmony_ci case kExprF32ReinterpretI32: 24021cb0ef41Sopenharmony_ci Movd(dst.fp(), src.gp()); 24031cb0ef41Sopenharmony_ci return true; 24041cb0ef41Sopenharmony_ci case kExprF64SConvertI32: 24051cb0ef41Sopenharmony_ci Cvtsi2sd(dst.fp(), src.gp()); 24061cb0ef41Sopenharmony_ci return true; 24071cb0ef41Sopenharmony_ci case kExprF64UConvertI32: { 24081cb0ef41Sopenharmony_ci LiftoffRegList pinned = {dst, src}; 24091cb0ef41Sopenharmony_ci Register scratch = GetUnusedRegister(kGpReg, pinned).gp(); 24101cb0ef41Sopenharmony_ci Cvtui2sd(dst.fp(), src.gp(), scratch); 24111cb0ef41Sopenharmony_ci return true; 24121cb0ef41Sopenharmony_ci } 24131cb0ef41Sopenharmony_ci case kExprF64ConvertF32: 24141cb0ef41Sopenharmony_ci cvtss2sd(dst.fp(), src.fp()); 24151cb0ef41Sopenharmony_ci return true; 24161cb0ef41Sopenharmony_ci case kExprF64ReinterpretI64: 24171cb0ef41Sopenharmony_ci // Push src to the stack. 24181cb0ef41Sopenharmony_ci push(src.high_gp()); 24191cb0ef41Sopenharmony_ci push(src.low_gp()); 24201cb0ef41Sopenharmony_ci // Pop to dst. 24211cb0ef41Sopenharmony_ci movsd(dst.fp(), Operand(esp, 0)); 24221cb0ef41Sopenharmony_ci add(esp, Immediate(8)); 24231cb0ef41Sopenharmony_ci return true; 24241cb0ef41Sopenharmony_ci default: 24251cb0ef41Sopenharmony_ci return false; 24261cb0ef41Sopenharmony_ci } 24271cb0ef41Sopenharmony_ci} 24281cb0ef41Sopenharmony_ci 24291cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_signextend_i8(Register dst, Register src) { 24301cb0ef41Sopenharmony_ci Register byte_reg = liftoff::GetTmpByteRegister(this, src); 24311cb0ef41Sopenharmony_ci if (byte_reg != src) mov(byte_reg, src); 24321cb0ef41Sopenharmony_ci movsx_b(dst, byte_reg); 24331cb0ef41Sopenharmony_ci} 24341cb0ef41Sopenharmony_ci 24351cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) { 24361cb0ef41Sopenharmony_ci movsx_w(dst, src); 24371cb0ef41Sopenharmony_ci} 24381cb0ef41Sopenharmony_ci 24391cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_signextend_i8(LiftoffRegister dst, 24401cb0ef41Sopenharmony_ci LiftoffRegister src) { 24411cb0ef41Sopenharmony_ci Register byte_reg = liftoff::GetTmpByteRegister(this, src.low_gp()); 24421cb0ef41Sopenharmony_ci if (byte_reg != src.low_gp()) mov(byte_reg, src.low_gp()); 24431cb0ef41Sopenharmony_ci movsx_b(dst.low_gp(), byte_reg); 24441cb0ef41Sopenharmony_ci liftoff::SignExtendI32ToI64(this, dst); 24451cb0ef41Sopenharmony_ci} 24461cb0ef41Sopenharmony_ci 24471cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_signextend_i16(LiftoffRegister dst, 24481cb0ef41Sopenharmony_ci LiftoffRegister src) { 24491cb0ef41Sopenharmony_ci movsx_w(dst.low_gp(), src.low_gp()); 24501cb0ef41Sopenharmony_ci liftoff::SignExtendI32ToI64(this, dst); 24511cb0ef41Sopenharmony_ci} 24521cb0ef41Sopenharmony_ci 24531cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_signextend_i32(LiftoffRegister dst, 24541cb0ef41Sopenharmony_ci LiftoffRegister src) { 24551cb0ef41Sopenharmony_ci if (dst.low_gp() != src.low_gp()) mov(dst.low_gp(), src.low_gp()); 24561cb0ef41Sopenharmony_ci liftoff::SignExtendI32ToI64(this, dst); 24571cb0ef41Sopenharmony_ci} 24581cb0ef41Sopenharmony_ci 24591cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_jump(Label* label) { jmp(label); } 24601cb0ef41Sopenharmony_ci 24611cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_jump(Register target) { jmp(target); } 24621cb0ef41Sopenharmony_ci 24631cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_cond_jump(LiftoffCondition liftoff_cond, 24641cb0ef41Sopenharmony_ci Label* label, ValueKind kind, 24651cb0ef41Sopenharmony_ci Register lhs, Register rhs) { 24661cb0ef41Sopenharmony_ci Condition cond = liftoff::ToCondition(liftoff_cond); 24671cb0ef41Sopenharmony_ci if (rhs != no_reg) { 24681cb0ef41Sopenharmony_ci switch (kind) { 24691cb0ef41Sopenharmony_ci case kRef: 24701cb0ef41Sopenharmony_ci case kOptRef: 24711cb0ef41Sopenharmony_ci case kRtt: 24721cb0ef41Sopenharmony_ci DCHECK(liftoff_cond == kEqual || liftoff_cond == kUnequal); 24731cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 24741cb0ef41Sopenharmony_ci case kI32: 24751cb0ef41Sopenharmony_ci cmp(lhs, rhs); 24761cb0ef41Sopenharmony_ci break; 24771cb0ef41Sopenharmony_ci default: 24781cb0ef41Sopenharmony_ci UNREACHABLE(); 24791cb0ef41Sopenharmony_ci } 24801cb0ef41Sopenharmony_ci } else { 24811cb0ef41Sopenharmony_ci DCHECK_EQ(kind, kI32); 24821cb0ef41Sopenharmony_ci test(lhs, lhs); 24831cb0ef41Sopenharmony_ci } 24841cb0ef41Sopenharmony_ci 24851cb0ef41Sopenharmony_ci j(cond, label); 24861cb0ef41Sopenharmony_ci} 24871cb0ef41Sopenharmony_ci 24881cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_cond_jumpi(LiftoffCondition liftoff_cond, 24891cb0ef41Sopenharmony_ci Label* label, Register lhs, 24901cb0ef41Sopenharmony_ci int imm) { 24911cb0ef41Sopenharmony_ci Condition cond = liftoff::ToCondition(liftoff_cond); 24921cb0ef41Sopenharmony_ci cmp(lhs, Immediate(imm)); 24931cb0ef41Sopenharmony_ci j(cond, label); 24941cb0ef41Sopenharmony_ci} 24951cb0ef41Sopenharmony_ci 24961cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_subi_jump_negative(Register value, 24971cb0ef41Sopenharmony_ci int subtrahend, 24981cb0ef41Sopenharmony_ci Label* result_negative) { 24991cb0ef41Sopenharmony_ci sub(value, Immediate(subtrahend)); 25001cb0ef41Sopenharmony_ci j(negative, result_negative); 25011cb0ef41Sopenharmony_ci} 25021cb0ef41Sopenharmony_ci 25031cb0ef41Sopenharmony_cinamespace liftoff { 25041cb0ef41Sopenharmony_ci 25051cb0ef41Sopenharmony_ci// Setcc into dst register, given a scratch byte register (might be the same as 25061cb0ef41Sopenharmony_ci// dst). Never spills. 25071cb0ef41Sopenharmony_ciinline void setcc_32_no_spill(LiftoffAssembler* assm, Condition cond, 25081cb0ef41Sopenharmony_ci Register dst, Register tmp_byte_reg) { 25091cb0ef41Sopenharmony_ci assm->setcc(cond, tmp_byte_reg); 25101cb0ef41Sopenharmony_ci assm->movzx_b(dst, tmp_byte_reg); 25111cb0ef41Sopenharmony_ci} 25121cb0ef41Sopenharmony_ci 25131cb0ef41Sopenharmony_ci// Setcc into dst register (no contraints). Might spill. 25141cb0ef41Sopenharmony_ciinline void setcc_32(LiftoffAssembler* assm, Condition cond, Register dst) { 25151cb0ef41Sopenharmony_ci Register tmp_byte_reg = GetTmpByteRegister(assm, dst); 25161cb0ef41Sopenharmony_ci setcc_32_no_spill(assm, cond, dst, tmp_byte_reg); 25171cb0ef41Sopenharmony_ci} 25181cb0ef41Sopenharmony_ci 25191cb0ef41Sopenharmony_ci} // namespace liftoff 25201cb0ef41Sopenharmony_ci 25211cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_eqz(Register dst, Register src) { 25221cb0ef41Sopenharmony_ci test(src, src); 25231cb0ef41Sopenharmony_ci liftoff::setcc_32(this, equal, dst); 25241cb0ef41Sopenharmony_ci} 25251cb0ef41Sopenharmony_ci 25261cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32_set_cond(LiftoffCondition liftoff_cond, 25271cb0ef41Sopenharmony_ci Register dst, Register lhs, 25281cb0ef41Sopenharmony_ci Register rhs) { 25291cb0ef41Sopenharmony_ci Condition cond = liftoff::ToCondition(liftoff_cond); 25301cb0ef41Sopenharmony_ci cmp(lhs, rhs); 25311cb0ef41Sopenharmony_ci liftoff::setcc_32(this, cond, dst); 25321cb0ef41Sopenharmony_ci} 25331cb0ef41Sopenharmony_ci 25341cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_eqz(Register dst, LiftoffRegister src) { 25351cb0ef41Sopenharmony_ci // Compute the OR of both registers in the src pair, using dst as scratch 25361cb0ef41Sopenharmony_ci // register. Then check whether the result is equal to zero. 25371cb0ef41Sopenharmony_ci if (src.low_gp() == dst) { 25381cb0ef41Sopenharmony_ci or_(dst, src.high_gp()); 25391cb0ef41Sopenharmony_ci } else { 25401cb0ef41Sopenharmony_ci if (src.high_gp() != dst) mov(dst, src.high_gp()); 25411cb0ef41Sopenharmony_ci or_(dst, src.low_gp()); 25421cb0ef41Sopenharmony_ci } 25431cb0ef41Sopenharmony_ci liftoff::setcc_32(this, equal, dst); 25441cb0ef41Sopenharmony_ci} 25451cb0ef41Sopenharmony_ci 25461cb0ef41Sopenharmony_cinamespace liftoff { 25471cb0ef41Sopenharmony_ciinline LiftoffCondition cond_make_unsigned(LiftoffCondition cond) { 25481cb0ef41Sopenharmony_ci switch (cond) { 25491cb0ef41Sopenharmony_ci case kSignedLessThan: 25501cb0ef41Sopenharmony_ci return kUnsignedLessThan; 25511cb0ef41Sopenharmony_ci case kSignedLessEqual: 25521cb0ef41Sopenharmony_ci return kUnsignedLessEqual; 25531cb0ef41Sopenharmony_ci case kSignedGreaterThan: 25541cb0ef41Sopenharmony_ci return kUnsignedGreaterThan; 25551cb0ef41Sopenharmony_ci case kSignedGreaterEqual: 25561cb0ef41Sopenharmony_ci return kUnsignedGreaterEqual; 25571cb0ef41Sopenharmony_ci default: 25581cb0ef41Sopenharmony_ci return cond; 25591cb0ef41Sopenharmony_ci } 25601cb0ef41Sopenharmony_ci} 25611cb0ef41Sopenharmony_ci} // namespace liftoff 25621cb0ef41Sopenharmony_ci 25631cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64_set_cond(LiftoffCondition liftoff_cond, 25641cb0ef41Sopenharmony_ci Register dst, LiftoffRegister lhs, 25651cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 25661cb0ef41Sopenharmony_ci Condition cond = liftoff::ToCondition(liftoff_cond); 25671cb0ef41Sopenharmony_ci Condition unsigned_cond = 25681cb0ef41Sopenharmony_ci liftoff::ToCondition(liftoff::cond_make_unsigned(liftoff_cond)); 25691cb0ef41Sopenharmony_ci 25701cb0ef41Sopenharmony_ci // Get the tmp byte register out here, such that we don't conditionally spill 25711cb0ef41Sopenharmony_ci // (this cannot be reflected in the cache state). 25721cb0ef41Sopenharmony_ci Register tmp_byte_reg = liftoff::GetTmpByteRegister(this, dst); 25731cb0ef41Sopenharmony_ci 25741cb0ef41Sopenharmony_ci // For signed i64 comparisons, we still need to use unsigned comparison for 25751cb0ef41Sopenharmony_ci // the low word (the only bit carrying signedness information is the MSB in 25761cb0ef41Sopenharmony_ci // the high word). 25771cb0ef41Sopenharmony_ci Label setcc; 25781cb0ef41Sopenharmony_ci Label cont; 25791cb0ef41Sopenharmony_ci // Compare high word first. If it differs, use if for the setcc. If it's 25801cb0ef41Sopenharmony_ci // equal, compare the low word and use that for setcc. 25811cb0ef41Sopenharmony_ci cmp(lhs.high_gp(), rhs.high_gp()); 25821cb0ef41Sopenharmony_ci j(not_equal, &setcc, Label::kNear); 25831cb0ef41Sopenharmony_ci cmp(lhs.low_gp(), rhs.low_gp()); 25841cb0ef41Sopenharmony_ci if (unsigned_cond != cond) { 25851cb0ef41Sopenharmony_ci // If the condition predicate for the low differs from that for the high 25861cb0ef41Sopenharmony_ci // word, emit a separete setcc sequence for the low word. 25871cb0ef41Sopenharmony_ci liftoff::setcc_32_no_spill(this, unsigned_cond, dst, tmp_byte_reg); 25881cb0ef41Sopenharmony_ci jmp(&cont); 25891cb0ef41Sopenharmony_ci } 25901cb0ef41Sopenharmony_ci bind(&setcc); 25911cb0ef41Sopenharmony_ci liftoff::setcc_32_no_spill(this, cond, dst, tmp_byte_reg); 25921cb0ef41Sopenharmony_ci bind(&cont); 25931cb0ef41Sopenharmony_ci} 25941cb0ef41Sopenharmony_ci 25951cb0ef41Sopenharmony_cinamespace liftoff { 25961cb0ef41Sopenharmony_citemplate <void (Assembler::*cmp_op)(DoubleRegister, DoubleRegister)> 25971cb0ef41Sopenharmony_civoid EmitFloatSetCond(LiftoffAssembler* assm, Condition cond, Register dst, 25981cb0ef41Sopenharmony_ci DoubleRegister lhs, DoubleRegister rhs) { 25991cb0ef41Sopenharmony_ci Label cont; 26001cb0ef41Sopenharmony_ci Label not_nan; 26011cb0ef41Sopenharmony_ci 26021cb0ef41Sopenharmony_ci // Get the tmp byte register out here, such that we don't conditionally spill 26031cb0ef41Sopenharmony_ci // (this cannot be reflected in the cache state). 26041cb0ef41Sopenharmony_ci Register tmp_byte_reg = GetTmpByteRegister(assm, dst); 26051cb0ef41Sopenharmony_ci 26061cb0ef41Sopenharmony_ci (assm->*cmp_op)(lhs, rhs); 26071cb0ef41Sopenharmony_ci // If PF is one, one of the operands was Nan. This needs special handling. 26081cb0ef41Sopenharmony_ci assm->j(parity_odd, ¬_nan, Label::kNear); 26091cb0ef41Sopenharmony_ci // Return 1 for f32.ne, 0 for all other cases. 26101cb0ef41Sopenharmony_ci if (cond == not_equal) { 26111cb0ef41Sopenharmony_ci assm->mov(dst, Immediate(1)); 26121cb0ef41Sopenharmony_ci } else { 26131cb0ef41Sopenharmony_ci assm->xor_(dst, dst); 26141cb0ef41Sopenharmony_ci } 26151cb0ef41Sopenharmony_ci assm->jmp(&cont, Label::kNear); 26161cb0ef41Sopenharmony_ci assm->bind(¬_nan); 26171cb0ef41Sopenharmony_ci 26181cb0ef41Sopenharmony_ci setcc_32_no_spill(assm, cond, dst, tmp_byte_reg); 26191cb0ef41Sopenharmony_ci assm->bind(&cont); 26201cb0ef41Sopenharmony_ci} 26211cb0ef41Sopenharmony_ci} // namespace liftoff 26221cb0ef41Sopenharmony_ci 26231cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32_set_cond(LiftoffCondition liftoff_cond, 26241cb0ef41Sopenharmony_ci Register dst, DoubleRegister lhs, 26251cb0ef41Sopenharmony_ci DoubleRegister rhs) { 26261cb0ef41Sopenharmony_ci Condition cond = liftoff::ToCondition(liftoff_cond); 26271cb0ef41Sopenharmony_ci liftoff::EmitFloatSetCond<&Assembler::ucomiss>(this, cond, dst, lhs, rhs); 26281cb0ef41Sopenharmony_ci} 26291cb0ef41Sopenharmony_ci 26301cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64_set_cond(LiftoffCondition liftoff_cond, 26311cb0ef41Sopenharmony_ci Register dst, DoubleRegister lhs, 26321cb0ef41Sopenharmony_ci DoubleRegister rhs) { 26331cb0ef41Sopenharmony_ci Condition cond = liftoff::ToCondition(liftoff_cond); 26341cb0ef41Sopenharmony_ci liftoff::EmitFloatSetCond<&Assembler::ucomisd>(this, cond, dst, lhs, rhs); 26351cb0ef41Sopenharmony_ci} 26361cb0ef41Sopenharmony_ci 26371cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition, 26381cb0ef41Sopenharmony_ci LiftoffRegister true_value, 26391cb0ef41Sopenharmony_ci LiftoffRegister false_value, 26401cb0ef41Sopenharmony_ci ValueKind kind) { 26411cb0ef41Sopenharmony_ci return false; 26421cb0ef41Sopenharmony_ci} 26431cb0ef41Sopenharmony_ci 26441cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_smi_check(Register obj, Label* target, 26451cb0ef41Sopenharmony_ci SmiCheckMode mode) { 26461cb0ef41Sopenharmony_ci test_b(obj, Immediate(kSmiTagMask)); 26471cb0ef41Sopenharmony_ci Condition condition = mode == kJumpOnSmi ? zero : not_zero; 26481cb0ef41Sopenharmony_ci j(condition, target); 26491cb0ef41Sopenharmony_ci} 26501cb0ef41Sopenharmony_ci 26511cb0ef41Sopenharmony_cinamespace liftoff { 26521cb0ef41Sopenharmony_citemplate <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister), 26531cb0ef41Sopenharmony_ci void (Assembler::*sse_op)(XMMRegister, XMMRegister)> 26541cb0ef41Sopenharmony_civoid EmitSimdCommutativeBinOp( 26551cb0ef41Sopenharmony_ci LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs, 26561cb0ef41Sopenharmony_ci LiftoffRegister rhs, base::Optional<CpuFeature> feature = base::nullopt) { 26571cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 26581cb0ef41Sopenharmony_ci CpuFeatureScope scope(assm, AVX); 26591cb0ef41Sopenharmony_ci (assm->*avx_op)(dst.fp(), lhs.fp(), rhs.fp()); 26601cb0ef41Sopenharmony_ci return; 26611cb0ef41Sopenharmony_ci } 26621cb0ef41Sopenharmony_ci 26631cb0ef41Sopenharmony_ci base::Optional<CpuFeatureScope> sse_scope; 26641cb0ef41Sopenharmony_ci if (feature.has_value()) sse_scope.emplace(assm, *feature); 26651cb0ef41Sopenharmony_ci 26661cb0ef41Sopenharmony_ci if (dst.fp() == rhs.fp()) { 26671cb0ef41Sopenharmony_ci (assm->*sse_op)(dst.fp(), lhs.fp()); 26681cb0ef41Sopenharmony_ci } else { 26691cb0ef41Sopenharmony_ci if (dst.fp() != lhs.fp()) (assm->movaps)(dst.fp(), lhs.fp()); 26701cb0ef41Sopenharmony_ci (assm->*sse_op)(dst.fp(), rhs.fp()); 26711cb0ef41Sopenharmony_ci } 26721cb0ef41Sopenharmony_ci} 26731cb0ef41Sopenharmony_ci 26741cb0ef41Sopenharmony_citemplate <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister), 26751cb0ef41Sopenharmony_ci void (Assembler::*sse_op)(XMMRegister, XMMRegister)> 26761cb0ef41Sopenharmony_civoid EmitSimdNonCommutativeBinOp( 26771cb0ef41Sopenharmony_ci LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs, 26781cb0ef41Sopenharmony_ci LiftoffRegister rhs, base::Optional<CpuFeature> feature = base::nullopt) { 26791cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 26801cb0ef41Sopenharmony_ci CpuFeatureScope scope(assm, AVX); 26811cb0ef41Sopenharmony_ci (assm->*avx_op)(dst.fp(), lhs.fp(), rhs.fp()); 26821cb0ef41Sopenharmony_ci return; 26831cb0ef41Sopenharmony_ci } 26841cb0ef41Sopenharmony_ci 26851cb0ef41Sopenharmony_ci base::Optional<CpuFeatureScope> sse_scope; 26861cb0ef41Sopenharmony_ci if (feature.has_value()) sse_scope.emplace(assm, *feature); 26871cb0ef41Sopenharmony_ci 26881cb0ef41Sopenharmony_ci if (dst.fp() == rhs.fp()) { 26891cb0ef41Sopenharmony_ci assm->movaps(kScratchDoubleReg, rhs.fp()); 26901cb0ef41Sopenharmony_ci assm->movaps(dst.fp(), lhs.fp()); 26911cb0ef41Sopenharmony_ci (assm->*sse_op)(dst.fp(), kScratchDoubleReg); 26921cb0ef41Sopenharmony_ci } else { 26931cb0ef41Sopenharmony_ci if (dst.fp() != lhs.fp()) assm->movaps(dst.fp(), lhs.fp()); 26941cb0ef41Sopenharmony_ci (assm->*sse_op)(dst.fp(), rhs.fp()); 26951cb0ef41Sopenharmony_ci } 26961cb0ef41Sopenharmony_ci} 26971cb0ef41Sopenharmony_ci 26981cb0ef41Sopenharmony_citemplate <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister), 26991cb0ef41Sopenharmony_ci void (Assembler::*sse_op)(XMMRegister, XMMRegister), uint8_t width> 27001cb0ef41Sopenharmony_civoid EmitSimdShiftOp(LiftoffAssembler* assm, LiftoffRegister dst, 27011cb0ef41Sopenharmony_ci LiftoffRegister operand, LiftoffRegister count) { 27021cb0ef41Sopenharmony_ci static constexpr RegClass tmp_rc = reg_class_for(kI32); 27031cb0ef41Sopenharmony_ci LiftoffRegister tmp = assm->GetUnusedRegister(tmp_rc, LiftoffRegList{count}); 27041cb0ef41Sopenharmony_ci constexpr int mask = (1 << width) - 1; 27051cb0ef41Sopenharmony_ci 27061cb0ef41Sopenharmony_ci assm->mov(tmp.gp(), count.gp()); 27071cb0ef41Sopenharmony_ci assm->and_(tmp.gp(), Immediate(mask)); 27081cb0ef41Sopenharmony_ci assm->Movd(kScratchDoubleReg, tmp.gp()); 27091cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 27101cb0ef41Sopenharmony_ci CpuFeatureScope scope(assm, AVX); 27111cb0ef41Sopenharmony_ci (assm->*avx_op)(dst.fp(), operand.fp(), kScratchDoubleReg); 27121cb0ef41Sopenharmony_ci } else { 27131cb0ef41Sopenharmony_ci if (dst.fp() != operand.fp()) assm->movaps(dst.fp(), operand.fp()); 27141cb0ef41Sopenharmony_ci (assm->*sse_op)(dst.fp(), kScratchDoubleReg); 27151cb0ef41Sopenharmony_ci } 27161cb0ef41Sopenharmony_ci} 27171cb0ef41Sopenharmony_ci 27181cb0ef41Sopenharmony_citemplate <void (Assembler::*avx_op)(XMMRegister, XMMRegister, byte), 27191cb0ef41Sopenharmony_ci void (Assembler::*sse_op)(XMMRegister, byte), uint8_t width> 27201cb0ef41Sopenharmony_civoid EmitSimdShiftOpImm(LiftoffAssembler* assm, LiftoffRegister dst, 27211cb0ef41Sopenharmony_ci LiftoffRegister operand, int32_t count) { 27221cb0ef41Sopenharmony_ci constexpr int mask = (1 << width) - 1; 27231cb0ef41Sopenharmony_ci byte shift = static_cast<byte>(count & mask); 27241cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 27251cb0ef41Sopenharmony_ci CpuFeatureScope scope(assm, AVX); 27261cb0ef41Sopenharmony_ci (assm->*avx_op)(dst.fp(), operand.fp(), shift); 27271cb0ef41Sopenharmony_ci } else { 27281cb0ef41Sopenharmony_ci if (dst.fp() != operand.fp()) assm->movaps(dst.fp(), operand.fp()); 27291cb0ef41Sopenharmony_ci (assm->*sse_op)(dst.fp(), shift); 27301cb0ef41Sopenharmony_ci } 27311cb0ef41Sopenharmony_ci} 27321cb0ef41Sopenharmony_ci 27331cb0ef41Sopenharmony_ciinline void EmitAnyTrue(LiftoffAssembler* assm, LiftoffRegister dst, 27341cb0ef41Sopenharmony_ci LiftoffRegister src) { 27351cb0ef41Sopenharmony_ci Register tmp = assm->GetUnusedRegister(kGpReg, LiftoffRegList{dst}).gp(); 27361cb0ef41Sopenharmony_ci assm->xor_(tmp, tmp); 27371cb0ef41Sopenharmony_ci assm->mov(dst.gp(), Immediate(1)); 27381cb0ef41Sopenharmony_ci assm->Ptest(src.fp(), src.fp()); 27391cb0ef41Sopenharmony_ci assm->cmov(zero, dst.gp(), tmp); 27401cb0ef41Sopenharmony_ci} 27411cb0ef41Sopenharmony_ci 27421cb0ef41Sopenharmony_citemplate <void (SharedTurboAssembler::*pcmp)(XMMRegister, XMMRegister)> 27431cb0ef41Sopenharmony_ciinline void EmitAllTrue(LiftoffAssembler* assm, LiftoffRegister dst, 27441cb0ef41Sopenharmony_ci LiftoffRegister src, 27451cb0ef41Sopenharmony_ci base::Optional<CpuFeature> feature = base::nullopt) { 27461cb0ef41Sopenharmony_ci base::Optional<CpuFeatureScope> sse_scope; 27471cb0ef41Sopenharmony_ci if (feature.has_value()) sse_scope.emplace(assm, *feature); 27481cb0ef41Sopenharmony_ci 27491cb0ef41Sopenharmony_ci Register tmp = assm->GetUnusedRegister(kGpReg, LiftoffRegList{dst}).gp(); 27501cb0ef41Sopenharmony_ci XMMRegister tmp_simd = liftoff::kScratchDoubleReg; 27511cb0ef41Sopenharmony_ci assm->mov(tmp, Immediate(1)); 27521cb0ef41Sopenharmony_ci assm->xor_(dst.gp(), dst.gp()); 27531cb0ef41Sopenharmony_ci assm->Pxor(tmp_simd, tmp_simd); 27541cb0ef41Sopenharmony_ci (assm->*pcmp)(tmp_simd, src.fp()); 27551cb0ef41Sopenharmony_ci assm->Ptest(tmp_simd, tmp_simd); 27561cb0ef41Sopenharmony_ci assm->cmov(zero, dst.gp(), tmp); 27571cb0ef41Sopenharmony_ci} 27581cb0ef41Sopenharmony_ci 27591cb0ef41Sopenharmony_ci} // namespace liftoff 27601cb0ef41Sopenharmony_ci 27611cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, 27621cb0ef41Sopenharmony_ci Register offset_reg, uintptr_t offset_imm, 27631cb0ef41Sopenharmony_ci LoadType type, 27641cb0ef41Sopenharmony_ci LoadTransformationKind transform, 27651cb0ef41Sopenharmony_ci uint32_t* protected_load_pc) { 27661cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 27671cb0ef41Sopenharmony_ci Operand src_op{src_addr, offset_reg, times_1, 27681cb0ef41Sopenharmony_ci static_cast<int32_t>(offset_imm)}; 27691cb0ef41Sopenharmony_ci *protected_load_pc = pc_offset(); 27701cb0ef41Sopenharmony_ci 27711cb0ef41Sopenharmony_ci MachineType memtype = type.mem_type(); 27721cb0ef41Sopenharmony_ci if (transform == LoadTransformationKind::kExtend) { 27731cb0ef41Sopenharmony_ci if (memtype == MachineType::Int8()) { 27741cb0ef41Sopenharmony_ci Pmovsxbw(dst.fp(), src_op); 27751cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Uint8()) { 27761cb0ef41Sopenharmony_ci Pmovzxbw(dst.fp(), src_op); 27771cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Int16()) { 27781cb0ef41Sopenharmony_ci Pmovsxwd(dst.fp(), src_op); 27791cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Uint16()) { 27801cb0ef41Sopenharmony_ci Pmovzxwd(dst.fp(), src_op); 27811cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Int32()) { 27821cb0ef41Sopenharmony_ci Pmovsxdq(dst.fp(), src_op); 27831cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Uint32()) { 27841cb0ef41Sopenharmony_ci Pmovzxdq(dst.fp(), src_op); 27851cb0ef41Sopenharmony_ci } 27861cb0ef41Sopenharmony_ci } else if (transform == LoadTransformationKind::kZeroExtend) { 27871cb0ef41Sopenharmony_ci if (memtype == MachineType::Int32()) { 27881cb0ef41Sopenharmony_ci Movss(dst.fp(), src_op); 27891cb0ef41Sopenharmony_ci } else { 27901cb0ef41Sopenharmony_ci DCHECK_EQ(MachineType::Int64(), memtype); 27911cb0ef41Sopenharmony_ci Movsd(dst.fp(), src_op); 27921cb0ef41Sopenharmony_ci } 27931cb0ef41Sopenharmony_ci } else { 27941cb0ef41Sopenharmony_ci DCHECK_EQ(LoadTransformationKind::kSplat, transform); 27951cb0ef41Sopenharmony_ci if (memtype == MachineType::Int8()) { 27961cb0ef41Sopenharmony_ci S128Load8Splat(dst.fp(), src_op, liftoff::kScratchDoubleReg); 27971cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Int16()) { 27981cb0ef41Sopenharmony_ci S128Load16Splat(dst.fp(), src_op, liftoff::kScratchDoubleReg); 27991cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Int32()) { 28001cb0ef41Sopenharmony_ci S128Load32Splat(dst.fp(), src_op); 28011cb0ef41Sopenharmony_ci } else if (memtype == MachineType::Int64()) { 28021cb0ef41Sopenharmony_ci Movddup(dst.fp(), src_op); 28031cb0ef41Sopenharmony_ci } 28041cb0ef41Sopenharmony_ci } 28051cb0ef41Sopenharmony_ci} 28061cb0ef41Sopenharmony_ci 28071cb0ef41Sopenharmony_civoid LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src, 28081cb0ef41Sopenharmony_ci Register addr, Register offset_reg, 28091cb0ef41Sopenharmony_ci uintptr_t offset_imm, LoadType type, 28101cb0ef41Sopenharmony_ci uint8_t laneidx, uint32_t* protected_load_pc) { 28111cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 28121cb0ef41Sopenharmony_ci Operand src_op{addr, offset_reg, times_1, static_cast<int32_t>(offset_imm)}; 28131cb0ef41Sopenharmony_ci *protected_load_pc = pc_offset(); 28141cb0ef41Sopenharmony_ci 28151cb0ef41Sopenharmony_ci MachineType mem_type = type.mem_type(); 28161cb0ef41Sopenharmony_ci if (mem_type == MachineType::Int8()) { 28171cb0ef41Sopenharmony_ci Pinsrb(dst.fp(), src.fp(), src_op, laneidx); 28181cb0ef41Sopenharmony_ci } else if (mem_type == MachineType::Int16()) { 28191cb0ef41Sopenharmony_ci Pinsrw(dst.fp(), src.fp(), src_op, laneidx); 28201cb0ef41Sopenharmony_ci } else if (mem_type == MachineType::Int32()) { 28211cb0ef41Sopenharmony_ci Pinsrd(dst.fp(), src.fp(), src_op, laneidx); 28221cb0ef41Sopenharmony_ci } else { 28231cb0ef41Sopenharmony_ci DCHECK_EQ(MachineType::Int64(), mem_type); 28241cb0ef41Sopenharmony_ci if (laneidx == 0) { 28251cb0ef41Sopenharmony_ci Movlps(dst.fp(), src.fp(), src_op); 28261cb0ef41Sopenharmony_ci } else { 28271cb0ef41Sopenharmony_ci DCHECK_EQ(1, laneidx); 28281cb0ef41Sopenharmony_ci Movhps(dst.fp(), src.fp(), src_op); 28291cb0ef41Sopenharmony_ci } 28301cb0ef41Sopenharmony_ci } 28311cb0ef41Sopenharmony_ci} 28321cb0ef41Sopenharmony_ci 28331cb0ef41Sopenharmony_civoid LiftoffAssembler::StoreLane(Register dst, Register offset, 28341cb0ef41Sopenharmony_ci uintptr_t offset_imm, LiftoffRegister src, 28351cb0ef41Sopenharmony_ci StoreType type, uint8_t lane, 28361cb0ef41Sopenharmony_ci uint32_t* protected_store_pc) { 28371cb0ef41Sopenharmony_ci DCHECK_LE(offset_imm, std::numeric_limits<int32_t>::max()); 28381cb0ef41Sopenharmony_ci Operand dst_op = Operand(dst, offset, times_1, offset_imm); 28391cb0ef41Sopenharmony_ci if (protected_store_pc) *protected_store_pc = pc_offset(); 28401cb0ef41Sopenharmony_ci 28411cb0ef41Sopenharmony_ci MachineRepresentation rep = type.mem_rep(); 28421cb0ef41Sopenharmony_ci if (rep == MachineRepresentation::kWord8) { 28431cb0ef41Sopenharmony_ci Pextrb(dst_op, src.fp(), lane); 28441cb0ef41Sopenharmony_ci } else if (rep == MachineRepresentation::kWord16) { 28451cb0ef41Sopenharmony_ci Pextrw(dst_op, src.fp(), lane); 28461cb0ef41Sopenharmony_ci } else if (rep == MachineRepresentation::kWord32) { 28471cb0ef41Sopenharmony_ci S128Store32Lane(dst_op, src.fp(), lane); 28481cb0ef41Sopenharmony_ci } else { 28491cb0ef41Sopenharmony_ci DCHECK_EQ(MachineRepresentation::kWord64, rep); 28501cb0ef41Sopenharmony_ci S128Store64Lane(dst_op, src.fp(), lane); 28511cb0ef41Sopenharmony_ci } 28521cb0ef41Sopenharmony_ci} 28531cb0ef41Sopenharmony_ci 28541cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shuffle(LiftoffRegister dst, 28551cb0ef41Sopenharmony_ci LiftoffRegister lhs, 28561cb0ef41Sopenharmony_ci LiftoffRegister rhs, 28571cb0ef41Sopenharmony_ci const uint8_t shuffle[16], 28581cb0ef41Sopenharmony_ci bool is_swizzle) { 28591cb0ef41Sopenharmony_ci LiftoffRegister tmp = GetUnusedRegister(kGpReg, {}); 28601cb0ef41Sopenharmony_ci // Prepare 16 byte aligned buffer for shuffle control mask. 28611cb0ef41Sopenharmony_ci mov(tmp.gp(), esp); 28621cb0ef41Sopenharmony_ci and_(esp, -16); 28631cb0ef41Sopenharmony_ci 28641cb0ef41Sopenharmony_ci if (is_swizzle) { 28651cb0ef41Sopenharmony_ci uint32_t imms[4]; 28661cb0ef41Sopenharmony_ci // Shuffles that use just 1 operand are called swizzles, rhs can be ignored. 28671cb0ef41Sopenharmony_ci wasm::SimdShuffle::Pack16Lanes(imms, shuffle); 28681cb0ef41Sopenharmony_ci for (int i = 3; i >= 0; i--) { 28691cb0ef41Sopenharmony_ci push_imm32(imms[i]); 28701cb0ef41Sopenharmony_ci } 28711cb0ef41Sopenharmony_ci Pshufb(dst.fp(), lhs.fp(), Operand(esp, 0)); 28721cb0ef41Sopenharmony_ci mov(esp, tmp.gp()); 28731cb0ef41Sopenharmony_ci return; 28741cb0ef41Sopenharmony_ci } 28751cb0ef41Sopenharmony_ci 28761cb0ef41Sopenharmony_ci movups(liftoff::kScratchDoubleReg, lhs.fp()); 28771cb0ef41Sopenharmony_ci for (int i = 3; i >= 0; i--) { 28781cb0ef41Sopenharmony_ci uint32_t mask = 0; 28791cb0ef41Sopenharmony_ci for (int j = 3; j >= 0; j--) { 28801cb0ef41Sopenharmony_ci uint8_t lane = shuffle[i * 4 + j]; 28811cb0ef41Sopenharmony_ci mask <<= 8; 28821cb0ef41Sopenharmony_ci mask |= lane < kSimd128Size ? lane : 0x80; 28831cb0ef41Sopenharmony_ci } 28841cb0ef41Sopenharmony_ci push(Immediate(mask)); 28851cb0ef41Sopenharmony_ci } 28861cb0ef41Sopenharmony_ci Pshufb(liftoff::kScratchDoubleReg, lhs.fp(), Operand(esp, 0)); 28871cb0ef41Sopenharmony_ci 28881cb0ef41Sopenharmony_ci for (int i = 3; i >= 0; i--) { 28891cb0ef41Sopenharmony_ci uint32_t mask = 0; 28901cb0ef41Sopenharmony_ci for (int j = 3; j >= 0; j--) { 28911cb0ef41Sopenharmony_ci uint8_t lane = shuffle[i * 4 + j]; 28921cb0ef41Sopenharmony_ci mask <<= 8; 28931cb0ef41Sopenharmony_ci mask |= lane >= kSimd128Size ? (lane & 0x0F) : 0x80; 28941cb0ef41Sopenharmony_ci } 28951cb0ef41Sopenharmony_ci push(Immediate(mask)); 28961cb0ef41Sopenharmony_ci } 28971cb0ef41Sopenharmony_ci Pshufb(dst.fp(), rhs.fp(), Operand(esp, 0)); 28981cb0ef41Sopenharmony_ci Por(dst.fp(), liftoff::kScratchDoubleReg); 28991cb0ef41Sopenharmony_ci mov(esp, tmp.gp()); 29001cb0ef41Sopenharmony_ci} 29011cb0ef41Sopenharmony_ci 29021cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst, 29031cb0ef41Sopenharmony_ci LiftoffRegister lhs, 29041cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 29051cb0ef41Sopenharmony_ci Register scratch = GetUnusedRegister(RegClass::kGpReg, {}).gp(); 29061cb0ef41Sopenharmony_ci I8x16Swizzle(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg, 29071cb0ef41Sopenharmony_ci scratch); 29081cb0ef41Sopenharmony_ci} 29091cb0ef41Sopenharmony_ci 29101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_popcnt(LiftoffRegister dst, 29111cb0ef41Sopenharmony_ci LiftoffRegister src) { 29121cb0ef41Sopenharmony_ci Register scratch = GetUnusedRegister(RegClass::kGpReg, {}).gp(); 29131cb0ef41Sopenharmony_ci XMMRegister tmp = 29141cb0ef41Sopenharmony_ci GetUnusedRegister(RegClass::kFpReg, LiftoffRegList{dst, src}).fp(); 29151cb0ef41Sopenharmony_ci I8x16Popcnt(dst.fp(), src.fp(), liftoff::kScratchDoubleReg, tmp, scratch); 29161cb0ef41Sopenharmony_ci} 29171cb0ef41Sopenharmony_ci 29181cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_splat(LiftoffRegister dst, 29191cb0ef41Sopenharmony_ci LiftoffRegister src) { 29201cb0ef41Sopenharmony_ci I8x16Splat(dst.fp(), src.gp(), liftoff::kScratchDoubleReg); 29211cb0ef41Sopenharmony_ci} 29221cb0ef41Sopenharmony_ci 29231cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_splat(LiftoffRegister dst, 29241cb0ef41Sopenharmony_ci LiftoffRegister src) { 29251cb0ef41Sopenharmony_ci I16x8Splat(dst.fp(), src.gp()); 29261cb0ef41Sopenharmony_ci} 29271cb0ef41Sopenharmony_ci 29281cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_splat(LiftoffRegister dst, 29291cb0ef41Sopenharmony_ci LiftoffRegister src) { 29301cb0ef41Sopenharmony_ci Movd(dst.fp(), src.gp()); 29311cb0ef41Sopenharmony_ci Pshufd(dst.fp(), dst.fp(), uint8_t{0}); 29321cb0ef41Sopenharmony_ci} 29331cb0ef41Sopenharmony_ci 29341cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_splat(LiftoffRegister dst, 29351cb0ef41Sopenharmony_ci LiftoffRegister src) { 29361cb0ef41Sopenharmony_ci Pinsrd(dst.fp(), src.low_gp(), 0); 29371cb0ef41Sopenharmony_ci Pinsrd(dst.fp(), src.high_gp(), 1); 29381cb0ef41Sopenharmony_ci Pshufd(dst.fp(), dst.fp(), uint8_t{0x44}); 29391cb0ef41Sopenharmony_ci} 29401cb0ef41Sopenharmony_ci 29411cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_splat(LiftoffRegister dst, 29421cb0ef41Sopenharmony_ci LiftoffRegister src) { 29431cb0ef41Sopenharmony_ci F32x4Splat(dst.fp(), src.fp()); 29441cb0ef41Sopenharmony_ci} 29451cb0ef41Sopenharmony_ci 29461cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_splat(LiftoffRegister dst, 29471cb0ef41Sopenharmony_ci LiftoffRegister src) { 29481cb0ef41Sopenharmony_ci Movddup(dst.fp(), src.fp()); 29491cb0ef41Sopenharmony_ci} 29501cb0ef41Sopenharmony_ci 29511cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs, 29521cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 29531cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqb, &Assembler::pcmpeqb>( 29541cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 29551cb0ef41Sopenharmony_ci} 29561cb0ef41Sopenharmony_ci 29571cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs, 29581cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 29591cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqb, &Assembler::pcmpeqb>( 29601cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 29611cb0ef41Sopenharmony_ci Pcmpeqb(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 29621cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 29631cb0ef41Sopenharmony_ci} 29641cb0ef41Sopenharmony_ci 29651cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 29661cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 29671cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpcmpgtb, 29681cb0ef41Sopenharmony_ci &Assembler::pcmpgtb>(this, dst, lhs, 29691cb0ef41Sopenharmony_ci rhs); 29701cb0ef41Sopenharmony_ci} 29711cb0ef41Sopenharmony_ci 29721cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs, 29731cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 29741cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 29751cb0ef41Sopenharmony_ci if (dst == rhs) { 29761cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 29771cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 29781cb0ef41Sopenharmony_ci } 29791cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxub, &Assembler::pmaxub>( 29801cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 29811cb0ef41Sopenharmony_ci Pcmpeqb(dst.fp(), ref); 29821cb0ef41Sopenharmony_ci Pcmpeqb(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 29831cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 29841cb0ef41Sopenharmony_ci} 29851cb0ef41Sopenharmony_ci 29861cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 29871cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 29881cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 29891cb0ef41Sopenharmony_ci if (dst == rhs) { 29901cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 29911cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 29921cb0ef41Sopenharmony_ci } 29931cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminsb, &Assembler::pminsb>( 29941cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 29951cb0ef41Sopenharmony_ci Pcmpeqb(dst.fp(), ref); 29961cb0ef41Sopenharmony_ci} 29971cb0ef41Sopenharmony_ci 29981cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs, 29991cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30001cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 30011cb0ef41Sopenharmony_ci if (dst == rhs) { 30021cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 30031cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 30041cb0ef41Sopenharmony_ci } 30051cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminub, &Assembler::pminub>( 30061cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 30071cb0ef41Sopenharmony_ci Pcmpeqb(dst.fp(), ref); 30081cb0ef41Sopenharmony_ci} 30091cb0ef41Sopenharmony_ci 30101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs, 30111cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30121cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqw, &Assembler::pcmpeqw>( 30131cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 30141cb0ef41Sopenharmony_ci} 30151cb0ef41Sopenharmony_ci 30161cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs, 30171cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30181cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqw, &Assembler::pcmpeqw>( 30191cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 30201cb0ef41Sopenharmony_ci Pcmpeqw(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 30211cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 30221cb0ef41Sopenharmony_ci} 30231cb0ef41Sopenharmony_ci 30241cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 30251cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30261cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpcmpgtw, 30271cb0ef41Sopenharmony_ci &Assembler::pcmpgtw>(this, dst, lhs, 30281cb0ef41Sopenharmony_ci rhs); 30291cb0ef41Sopenharmony_ci} 30301cb0ef41Sopenharmony_ci 30311cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs, 30321cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30331cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 30341cb0ef41Sopenharmony_ci if (dst == rhs) { 30351cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 30361cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 30371cb0ef41Sopenharmony_ci } 30381cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxuw, &Assembler::pmaxuw>( 30391cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 30401cb0ef41Sopenharmony_ci Pcmpeqw(dst.fp(), ref); 30411cb0ef41Sopenharmony_ci Pcmpeqw(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 30421cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 30431cb0ef41Sopenharmony_ci} 30441cb0ef41Sopenharmony_ci 30451cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 30461cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30471cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 30481cb0ef41Sopenharmony_ci if (dst == rhs) { 30491cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 30501cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 30511cb0ef41Sopenharmony_ci } 30521cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminsw, &Assembler::pminsw>( 30531cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 30541cb0ef41Sopenharmony_ci Pcmpeqw(dst.fp(), ref); 30551cb0ef41Sopenharmony_ci} 30561cb0ef41Sopenharmony_ci 30571cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs, 30581cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30591cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 30601cb0ef41Sopenharmony_ci if (dst == rhs) { 30611cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 30621cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 30631cb0ef41Sopenharmony_ci } 30641cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminuw, &Assembler::pminuw>( 30651cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 30661cb0ef41Sopenharmony_ci Pcmpeqw(dst.fp(), ref); 30671cb0ef41Sopenharmony_ci} 30681cb0ef41Sopenharmony_ci 30691cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, 30701cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30711cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqd, &Assembler::pcmpeqd>( 30721cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 30731cb0ef41Sopenharmony_ci} 30741cb0ef41Sopenharmony_ci 30751cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, 30761cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30771cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqd, &Assembler::pcmpeqd>( 30781cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 30791cb0ef41Sopenharmony_ci Pcmpeqd(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 30801cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 30811cb0ef41Sopenharmony_ci} 30821cb0ef41Sopenharmony_ci 30831cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 30841cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30851cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpcmpgtd, 30861cb0ef41Sopenharmony_ci &Assembler::pcmpgtd>(this, dst, lhs, 30871cb0ef41Sopenharmony_ci rhs); 30881cb0ef41Sopenharmony_ci} 30891cb0ef41Sopenharmony_ci 30901cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs, 30911cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 30921cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 30931cb0ef41Sopenharmony_ci if (dst == rhs) { 30941cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 30951cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 30961cb0ef41Sopenharmony_ci } 30971cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxud, &Assembler::pmaxud>( 30981cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 30991cb0ef41Sopenharmony_ci Pcmpeqd(dst.fp(), ref); 31001cb0ef41Sopenharmony_ci Pcmpeqd(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 31011cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 31021cb0ef41Sopenharmony_ci} 31031cb0ef41Sopenharmony_ci 31041cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 31051cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31061cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 31071cb0ef41Sopenharmony_ci if (dst == rhs) { 31081cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 31091cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 31101cb0ef41Sopenharmony_ci } 31111cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminsd, &Assembler::pminsd>( 31121cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 31131cb0ef41Sopenharmony_ci Pcmpeqd(dst.fp(), ref); 31141cb0ef41Sopenharmony_ci} 31151cb0ef41Sopenharmony_ci 31161cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs, 31171cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31181cb0ef41Sopenharmony_ci DoubleRegister ref = rhs.fp(); 31191cb0ef41Sopenharmony_ci if (dst == rhs) { 31201cb0ef41Sopenharmony_ci Movaps(liftoff::kScratchDoubleReg, rhs.fp()); 31211cb0ef41Sopenharmony_ci ref = liftoff::kScratchDoubleReg; 31221cb0ef41Sopenharmony_ci } 31231cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminud, &Assembler::pminud>( 31241cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 31251cb0ef41Sopenharmony_ci Pcmpeqd(dst.fp(), ref); 31261cb0ef41Sopenharmony_ci} 31271cb0ef41Sopenharmony_ci 31281cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, 31291cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31301cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqq, &Assembler::pcmpeqq>( 31311cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 31321cb0ef41Sopenharmony_ci} 31331cb0ef41Sopenharmony_ci 31341cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, 31351cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31361cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpcmpeqq, &Assembler::pcmpeqq>( 31371cb0ef41Sopenharmony_ci this, dst, lhs, rhs, SSE4_1); 31381cb0ef41Sopenharmony_ci Pcmpeqq(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 31391cb0ef41Sopenharmony_ci Pxor(dst.fp(), liftoff::kScratchDoubleReg); 31401cb0ef41Sopenharmony_ci} 31411cb0ef41Sopenharmony_ci 31421cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 31431cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31441cb0ef41Sopenharmony_ci // Different register alias requirements depending on CpuFeatures supported: 31451cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX) || CpuFeatures::IsSupported(SSE4_2)) { 31461cb0ef41Sopenharmony_ci // 1. AVX, or SSE4_2 no requirements (I64x2GtS takes care of aliasing). 31471cb0ef41Sopenharmony_ci I64x2GtS(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31481cb0ef41Sopenharmony_ci } else { 31491cb0ef41Sopenharmony_ci // 2. Else, dst != lhs && dst != rhs (lhs == rhs is ok). 31501cb0ef41Sopenharmony_ci if (dst == lhs || dst == rhs) { 31511cb0ef41Sopenharmony_ci LiftoffRegister tmp = 31521cb0ef41Sopenharmony_ci GetUnusedRegister(RegClass::kFpReg, LiftoffRegList{lhs, rhs}); 31531cb0ef41Sopenharmony_ci I64x2GtS(tmp.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31541cb0ef41Sopenharmony_ci movaps(dst.fp(), tmp.fp()); 31551cb0ef41Sopenharmony_ci } else { 31561cb0ef41Sopenharmony_ci I64x2GtS(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31571cb0ef41Sopenharmony_ci } 31581cb0ef41Sopenharmony_ci } 31591cb0ef41Sopenharmony_ci} 31601cb0ef41Sopenharmony_ci 31611cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 31621cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31631cb0ef41Sopenharmony_ci // Different register alias requirements depending on CpuFeatures supported: 31641cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 31651cb0ef41Sopenharmony_ci // 1. AVX, no requirements. 31661cb0ef41Sopenharmony_ci I64x2GeS(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31671cb0ef41Sopenharmony_ci } else if (CpuFeatures::IsSupported(SSE4_2)) { 31681cb0ef41Sopenharmony_ci // 2. SSE4_2, dst != lhs. 31691cb0ef41Sopenharmony_ci if (dst == lhs) { 31701cb0ef41Sopenharmony_ci LiftoffRegister tmp = 31711cb0ef41Sopenharmony_ci GetUnusedRegister(RegClass::kFpReg, {rhs}, LiftoffRegList{lhs}); 31721cb0ef41Sopenharmony_ci // macro-assembler uses kScratchDoubleReg, so don't use it. 31731cb0ef41Sopenharmony_ci I64x2GeS(tmp.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31741cb0ef41Sopenharmony_ci movaps(dst.fp(), tmp.fp()); 31751cb0ef41Sopenharmony_ci } else { 31761cb0ef41Sopenharmony_ci I64x2GeS(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31771cb0ef41Sopenharmony_ci } 31781cb0ef41Sopenharmony_ci } else { 31791cb0ef41Sopenharmony_ci // 3. Else, dst != lhs && dst != rhs (lhs == rhs is ok). 31801cb0ef41Sopenharmony_ci if (dst == lhs || dst == rhs) { 31811cb0ef41Sopenharmony_ci LiftoffRegister tmp = 31821cb0ef41Sopenharmony_ci GetUnusedRegister(RegClass::kFpReg, LiftoffRegList{lhs, rhs}); 31831cb0ef41Sopenharmony_ci I64x2GeS(tmp.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31841cb0ef41Sopenharmony_ci movaps(dst.fp(), tmp.fp()); 31851cb0ef41Sopenharmony_ci } else { 31861cb0ef41Sopenharmony_ci I64x2GeS(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 31871cb0ef41Sopenharmony_ci } 31881cb0ef41Sopenharmony_ci } 31891cb0ef41Sopenharmony_ci} 31901cb0ef41Sopenharmony_ci 31911cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, 31921cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31931cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vcmpeqps, &Assembler::cmpeqps>( 31941cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 31951cb0ef41Sopenharmony_ci} 31961cb0ef41Sopenharmony_ci 31971cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, 31981cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 31991cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vcmpneqps, 32001cb0ef41Sopenharmony_ci &Assembler::cmpneqps>(this, dst, lhs, rhs); 32011cb0ef41Sopenharmony_ci} 32021cb0ef41Sopenharmony_ci 32031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs, 32041cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32051cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmpltps, 32061cb0ef41Sopenharmony_ci &Assembler::cmpltps>(this, dst, lhs, 32071cb0ef41Sopenharmony_ci rhs); 32081cb0ef41Sopenharmony_ci} 32091cb0ef41Sopenharmony_ci 32101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs, 32111cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32121cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmpleps, 32131cb0ef41Sopenharmony_ci &Assembler::cmpleps>(this, dst, lhs, 32141cb0ef41Sopenharmony_ci rhs); 32151cb0ef41Sopenharmony_ci} 32161cb0ef41Sopenharmony_ci 32171cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, 32181cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32191cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vcmpeqpd, &Assembler::cmpeqpd>( 32201cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 32211cb0ef41Sopenharmony_ci} 32221cb0ef41Sopenharmony_ci 32231cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, 32241cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32251cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vcmpneqpd, 32261cb0ef41Sopenharmony_ci &Assembler::cmpneqpd>(this, dst, lhs, rhs); 32271cb0ef41Sopenharmony_ci} 32281cb0ef41Sopenharmony_ci 32291cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs, 32301cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32311cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmpltpd, 32321cb0ef41Sopenharmony_ci &Assembler::cmpltpd>(this, dst, lhs, 32331cb0ef41Sopenharmony_ci rhs); 32341cb0ef41Sopenharmony_ci} 32351cb0ef41Sopenharmony_ci 32361cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs, 32371cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32381cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmplepd, 32391cb0ef41Sopenharmony_ci &Assembler::cmplepd>(this, dst, lhs, 32401cb0ef41Sopenharmony_ci rhs); 32411cb0ef41Sopenharmony_ci} 32421cb0ef41Sopenharmony_ci 32431cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_const(LiftoffRegister dst, 32441cb0ef41Sopenharmony_ci const uint8_t imms[16]) { 32451cb0ef41Sopenharmony_ci uint64_t vals[2]; 32461cb0ef41Sopenharmony_ci memcpy(vals, imms, sizeof(vals)); 32471cb0ef41Sopenharmony_ci TurboAssembler::Move(dst.fp(), vals[0]); 32481cb0ef41Sopenharmony_ci 32491cb0ef41Sopenharmony_ci uint64_t high = vals[1]; 32501cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(RegClass::kGpReg, {}).gp(); 32511cb0ef41Sopenharmony_ci TurboAssembler::Move(tmp, Immediate(high & 0xffff'ffff)); 32521cb0ef41Sopenharmony_ci Pinsrd(dst.fp(), tmp, 2); 32531cb0ef41Sopenharmony_ci 32541cb0ef41Sopenharmony_ci TurboAssembler::Move(tmp, Immediate(high >> 32)); 32551cb0ef41Sopenharmony_ci Pinsrd(dst.fp(), tmp, 3); 32561cb0ef41Sopenharmony_ci} 32571cb0ef41Sopenharmony_ci 32581cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_not(LiftoffRegister dst, LiftoffRegister src) { 32591cb0ef41Sopenharmony_ci S128Not(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 32601cb0ef41Sopenharmony_ci} 32611cb0ef41Sopenharmony_ci 32621cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs, 32631cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32641cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpand, &Assembler::pand>( 32651cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 32661cb0ef41Sopenharmony_ci} 32671cb0ef41Sopenharmony_ci 32681cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs, 32691cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32701cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpor, &Assembler::por>( 32711cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 32721cb0ef41Sopenharmony_ci} 32731cb0ef41Sopenharmony_ci 32741cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs, 32751cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 32761cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpxor, &Assembler::pxor>( 32771cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 32781cb0ef41Sopenharmony_ci} 32791cb0ef41Sopenharmony_ci 32801cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_select(LiftoffRegister dst, 32811cb0ef41Sopenharmony_ci LiftoffRegister src1, 32821cb0ef41Sopenharmony_ci LiftoffRegister src2, 32831cb0ef41Sopenharmony_ci LiftoffRegister mask) { 32841cb0ef41Sopenharmony_ci // Ensure that we don't overwrite any inputs with the movaps below. 32851cb0ef41Sopenharmony_ci DCHECK_NE(dst, src1); 32861cb0ef41Sopenharmony_ci DCHECK_NE(dst, src2); 32871cb0ef41Sopenharmony_ci if (!CpuFeatures::IsSupported(AVX) && dst != mask) { 32881cb0ef41Sopenharmony_ci movaps(dst.fp(), mask.fp()); 32891cb0ef41Sopenharmony_ci S128Select(dst.fp(), dst.fp(), src1.fp(), src2.fp(), 32901cb0ef41Sopenharmony_ci liftoff::kScratchDoubleReg); 32911cb0ef41Sopenharmony_ci } else { 32921cb0ef41Sopenharmony_ci S128Select(dst.fp(), mask.fp(), src1.fp(), src2.fp(), 32931cb0ef41Sopenharmony_ci liftoff::kScratchDoubleReg); 32941cb0ef41Sopenharmony_ci } 32951cb0ef41Sopenharmony_ci} 32961cb0ef41Sopenharmony_ci 32971cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_neg(LiftoffRegister dst, 32981cb0ef41Sopenharmony_ci LiftoffRegister src) { 32991cb0ef41Sopenharmony_ci if (dst.fp() == src.fp()) { 33001cb0ef41Sopenharmony_ci Pcmpeqd(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 33011cb0ef41Sopenharmony_ci Psignb(dst.fp(), liftoff::kScratchDoubleReg); 33021cb0ef41Sopenharmony_ci } else { 33031cb0ef41Sopenharmony_ci Pxor(dst.fp(), dst.fp()); 33041cb0ef41Sopenharmony_ci Psubb(dst.fp(), src.fp()); 33051cb0ef41Sopenharmony_ci } 33061cb0ef41Sopenharmony_ci} 33071cb0ef41Sopenharmony_ci 33081cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_v128_anytrue(LiftoffRegister dst, 33091cb0ef41Sopenharmony_ci LiftoffRegister src) { 33101cb0ef41Sopenharmony_ci liftoff::EmitAnyTrue(this, dst, src); 33111cb0ef41Sopenharmony_ci} 33121cb0ef41Sopenharmony_ci 33131cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_alltrue(LiftoffRegister dst, 33141cb0ef41Sopenharmony_ci LiftoffRegister src) { 33151cb0ef41Sopenharmony_ci liftoff::EmitAllTrue<&TurboAssembler::Pcmpeqb>(this, dst, src); 33161cb0ef41Sopenharmony_ci} 33171cb0ef41Sopenharmony_ci 33181cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_bitmask(LiftoffRegister dst, 33191cb0ef41Sopenharmony_ci LiftoffRegister src) { 33201cb0ef41Sopenharmony_ci Pmovmskb(dst.gp(), src.fp()); 33211cb0ef41Sopenharmony_ci} 33221cb0ef41Sopenharmony_ci 33231cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs, 33241cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33251cb0ef41Sopenharmony_ci LiftoffRegister tmp = GetUnusedRegister(kGpReg, LiftoffRegList{rhs}); 33261cb0ef41Sopenharmony_ci LiftoffRegister tmp_simd = 33271cb0ef41Sopenharmony_ci GetUnusedRegister(kFpReg, LiftoffRegList{dst, lhs}); 33281cb0ef41Sopenharmony_ci I8x16Shl(dst.fp(), lhs.fp(), rhs.gp(), tmp.gp(), liftoff::kScratchDoubleReg, 33291cb0ef41Sopenharmony_ci tmp_simd.fp()); 33301cb0ef41Sopenharmony_ci} 33311cb0ef41Sopenharmony_ci 33321cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs, 33331cb0ef41Sopenharmony_ci int32_t rhs) { 33341cb0ef41Sopenharmony_ci LiftoffRegister tmp = GetUnusedRegister(kGpReg, {}); 33351cb0ef41Sopenharmony_ci I8x16Shl(dst.fp(), lhs.fp(), rhs, tmp.gp(), liftoff::kScratchDoubleReg); 33361cb0ef41Sopenharmony_ci} 33371cb0ef41Sopenharmony_ci 33381cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shr_s(LiftoffRegister dst, 33391cb0ef41Sopenharmony_ci LiftoffRegister lhs, 33401cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33411cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, LiftoffRegList{rhs}).gp(); 33421cb0ef41Sopenharmony_ci XMMRegister tmp_simd = 33431cb0ef41Sopenharmony_ci GetUnusedRegister(kFpReg, LiftoffRegList{dst, lhs}).fp(); 33441cb0ef41Sopenharmony_ci I8x16ShrS(dst.fp(), lhs.fp(), rhs.gp(), tmp, liftoff::kScratchDoubleReg, 33451cb0ef41Sopenharmony_ci tmp_simd); 33461cb0ef41Sopenharmony_ci} 33471cb0ef41Sopenharmony_ci 33481cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shri_s(LiftoffRegister dst, 33491cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 33501cb0ef41Sopenharmony_ci I8x16ShrS(dst.fp(), lhs.fp(), rhs, liftoff::kScratchDoubleReg); 33511cb0ef41Sopenharmony_ci} 33521cb0ef41Sopenharmony_ci 33531cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shr_u(LiftoffRegister dst, 33541cb0ef41Sopenharmony_ci LiftoffRegister lhs, 33551cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33561cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, LiftoffRegList{rhs}).gp(); 33571cb0ef41Sopenharmony_ci XMMRegister tmp_simd = 33581cb0ef41Sopenharmony_ci GetUnusedRegister(kFpReg, LiftoffRegList{dst, lhs}).fp(); 33591cb0ef41Sopenharmony_ci I8x16ShrU(dst.fp(), lhs.fp(), rhs.gp(), tmp, liftoff::kScratchDoubleReg, 33601cb0ef41Sopenharmony_ci tmp_simd); 33611cb0ef41Sopenharmony_ci} 33621cb0ef41Sopenharmony_ci 33631cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_shri_u(LiftoffRegister dst, 33641cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 33651cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 33661cb0ef41Sopenharmony_ci I8x16ShrU(dst.fp(), lhs.fp(), rhs, tmp, liftoff::kScratchDoubleReg); 33671cb0ef41Sopenharmony_ci} 33681cb0ef41Sopenharmony_ci 33691cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs, 33701cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33711cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddb, &Assembler::paddb>( 33721cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 33731cb0ef41Sopenharmony_ci} 33741cb0ef41Sopenharmony_ci 33751cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_add_sat_s(LiftoffRegister dst, 33761cb0ef41Sopenharmony_ci LiftoffRegister lhs, 33771cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33781cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddsb, &Assembler::paddsb>( 33791cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 33801cb0ef41Sopenharmony_ci} 33811cb0ef41Sopenharmony_ci 33821cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_add_sat_u(LiftoffRegister dst, 33831cb0ef41Sopenharmony_ci LiftoffRegister lhs, 33841cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33851cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddusb, &Assembler::paddusb>( 33861cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 33871cb0ef41Sopenharmony_ci} 33881cb0ef41Sopenharmony_ci 33891cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs, 33901cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33911cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubb, &Assembler::psubb>( 33921cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 33931cb0ef41Sopenharmony_ci} 33941cb0ef41Sopenharmony_ci 33951cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_sub_sat_s(LiftoffRegister dst, 33961cb0ef41Sopenharmony_ci LiftoffRegister lhs, 33971cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 33981cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubsb, &Assembler::psubsb>( 33991cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 34001cb0ef41Sopenharmony_ci} 34011cb0ef41Sopenharmony_ci 34021cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_sub_sat_u(LiftoffRegister dst, 34031cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34041cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34051cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubusb, 34061cb0ef41Sopenharmony_ci &Assembler::psubusb>(this, dst, lhs, 34071cb0ef41Sopenharmony_ci rhs); 34081cb0ef41Sopenharmony_ci} 34091cb0ef41Sopenharmony_ci 34101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_min_s(LiftoffRegister dst, 34111cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34121cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34131cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminsb, &Assembler::pminsb>( 34141cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 34151cb0ef41Sopenharmony_ci} 34161cb0ef41Sopenharmony_ci 34171cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_min_u(LiftoffRegister dst, 34181cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34191cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34201cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminub, &Assembler::pminub>( 34211cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 34221cb0ef41Sopenharmony_ci} 34231cb0ef41Sopenharmony_ci 34241cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_max_s(LiftoffRegister dst, 34251cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34261cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34271cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxsb, &Assembler::pmaxsb>( 34281cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 34291cb0ef41Sopenharmony_ci} 34301cb0ef41Sopenharmony_ci 34311cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_max_u(LiftoffRegister dst, 34321cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34331cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34341cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxub, &Assembler::pmaxub>( 34351cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 34361cb0ef41Sopenharmony_ci} 34371cb0ef41Sopenharmony_ci 34381cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_neg(LiftoffRegister dst, 34391cb0ef41Sopenharmony_ci LiftoffRegister src) { 34401cb0ef41Sopenharmony_ci if (dst.fp() == src.fp()) { 34411cb0ef41Sopenharmony_ci Pcmpeqd(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 34421cb0ef41Sopenharmony_ci Psignw(dst.fp(), liftoff::kScratchDoubleReg); 34431cb0ef41Sopenharmony_ci } else { 34441cb0ef41Sopenharmony_ci Pxor(dst.fp(), dst.fp()); 34451cb0ef41Sopenharmony_ci Psubw(dst.fp(), src.fp()); 34461cb0ef41Sopenharmony_ci } 34471cb0ef41Sopenharmony_ci} 34481cb0ef41Sopenharmony_ci 34491cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_alltrue(LiftoffRegister dst, 34501cb0ef41Sopenharmony_ci LiftoffRegister src) { 34511cb0ef41Sopenharmony_ci liftoff::EmitAllTrue<&TurboAssembler::Pcmpeqw>(this, dst, src); 34521cb0ef41Sopenharmony_ci} 34531cb0ef41Sopenharmony_ci 34541cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_bitmask(LiftoffRegister dst, 34551cb0ef41Sopenharmony_ci LiftoffRegister src) { 34561cb0ef41Sopenharmony_ci XMMRegister tmp = liftoff::kScratchDoubleReg; 34571cb0ef41Sopenharmony_ci Packsswb(tmp, src.fp()); 34581cb0ef41Sopenharmony_ci Pmovmskb(dst.gp(), tmp); 34591cb0ef41Sopenharmony_ci shr(dst.gp(), 8); 34601cb0ef41Sopenharmony_ci} 34611cb0ef41Sopenharmony_ci 34621cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs, 34631cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34641cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsllw, &Assembler::psllw, 4>(this, dst, 34651cb0ef41Sopenharmony_ci lhs, rhs); 34661cb0ef41Sopenharmony_ci} 34671cb0ef41Sopenharmony_ci 34681cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs, 34691cb0ef41Sopenharmony_ci int32_t rhs) { 34701cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsllw, &Assembler::psllw, 4>( 34711cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 34721cb0ef41Sopenharmony_ci} 34731cb0ef41Sopenharmony_ci 34741cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_shr_s(LiftoffRegister dst, 34751cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34761cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34771cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsraw, &Assembler::psraw, 4>(this, dst, 34781cb0ef41Sopenharmony_ci lhs, rhs); 34791cb0ef41Sopenharmony_ci} 34801cb0ef41Sopenharmony_ci 34811cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_shri_s(LiftoffRegister dst, 34821cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 34831cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsraw, &Assembler::psraw, 4>( 34841cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 34851cb0ef41Sopenharmony_ci} 34861cb0ef41Sopenharmony_ci 34871cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_shr_u(LiftoffRegister dst, 34881cb0ef41Sopenharmony_ci LiftoffRegister lhs, 34891cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 34901cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsrlw, &Assembler::psrlw, 4>(this, dst, 34911cb0ef41Sopenharmony_ci lhs, rhs); 34921cb0ef41Sopenharmony_ci} 34931cb0ef41Sopenharmony_ci 34941cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_shri_u(LiftoffRegister dst, 34951cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 34961cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsrlw, &Assembler::psrlw, 4>( 34971cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 34981cb0ef41Sopenharmony_ci} 34991cb0ef41Sopenharmony_ci 35001cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs, 35011cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35021cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddw, &Assembler::paddw>( 35031cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35041cb0ef41Sopenharmony_ci} 35051cb0ef41Sopenharmony_ci 35061cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_add_sat_s(LiftoffRegister dst, 35071cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35081cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35091cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddsw, &Assembler::paddsw>( 35101cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35111cb0ef41Sopenharmony_ci} 35121cb0ef41Sopenharmony_ci 35131cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_add_sat_u(LiftoffRegister dst, 35141cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35151cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35161cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddusw, &Assembler::paddusw>( 35171cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35181cb0ef41Sopenharmony_ci} 35191cb0ef41Sopenharmony_ci 35201cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs, 35211cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35221cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubw, &Assembler::psubw>( 35231cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35241cb0ef41Sopenharmony_ci} 35251cb0ef41Sopenharmony_ci 35261cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_sub_sat_s(LiftoffRegister dst, 35271cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35281cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35291cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubsw, &Assembler::psubsw>( 35301cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35311cb0ef41Sopenharmony_ci} 35321cb0ef41Sopenharmony_ci 35331cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_sub_sat_u(LiftoffRegister dst, 35341cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35351cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35361cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubusw, 35371cb0ef41Sopenharmony_ci &Assembler::psubusw>(this, dst, lhs, 35381cb0ef41Sopenharmony_ci rhs); 35391cb0ef41Sopenharmony_ci} 35401cb0ef41Sopenharmony_ci 35411cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs, 35421cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35431cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmullw, &Assembler::pmullw>( 35441cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35451cb0ef41Sopenharmony_ci} 35461cb0ef41Sopenharmony_ci 35471cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_min_s(LiftoffRegister dst, 35481cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35491cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35501cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminsw, &Assembler::pminsw>( 35511cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35521cb0ef41Sopenharmony_ci} 35531cb0ef41Sopenharmony_ci 35541cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_min_u(LiftoffRegister dst, 35551cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35561cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35571cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminuw, &Assembler::pminuw>( 35581cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 35591cb0ef41Sopenharmony_ci} 35601cb0ef41Sopenharmony_ci 35611cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_max_s(LiftoffRegister dst, 35621cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35631cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35641cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxsw, &Assembler::pmaxsw>( 35651cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 35661cb0ef41Sopenharmony_ci} 35671cb0ef41Sopenharmony_ci 35681cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_max_u(LiftoffRegister dst, 35691cb0ef41Sopenharmony_ci LiftoffRegister lhs, 35701cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 35711cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxuw, &Assembler::pmaxuw>( 35721cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 35731cb0ef41Sopenharmony_ci} 35741cb0ef41Sopenharmony_ci 35751cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extadd_pairwise_i8x16_s(LiftoffRegister dst, 35761cb0ef41Sopenharmony_ci LiftoffRegister src) { 35771cb0ef41Sopenharmony_ci I16x8ExtAddPairwiseI8x16S(dst.fp(), src.fp(), liftoff::kScratchDoubleReg, 35781cb0ef41Sopenharmony_ci GetUnusedRegister(kGpReg, {}).gp()); 35791cb0ef41Sopenharmony_ci} 35801cb0ef41Sopenharmony_ci 35811cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extadd_pairwise_i8x16_u(LiftoffRegister dst, 35821cb0ef41Sopenharmony_ci LiftoffRegister src) { 35831cb0ef41Sopenharmony_ci I16x8ExtAddPairwiseI8x16U(dst.fp(), src.fp(), 35841cb0ef41Sopenharmony_ci GetUnusedRegister(kGpReg, {}).gp()); 35851cb0ef41Sopenharmony_ci} 35861cb0ef41Sopenharmony_ci 35871cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extmul_low_i8x16_s(LiftoffRegister dst, 35881cb0ef41Sopenharmony_ci LiftoffRegister src1, 35891cb0ef41Sopenharmony_ci LiftoffRegister src2) { 35901cb0ef41Sopenharmony_ci I16x8ExtMulLow(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg, 35911cb0ef41Sopenharmony_ci /*is_signed=*/true); 35921cb0ef41Sopenharmony_ci} 35931cb0ef41Sopenharmony_ci 35941cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extmul_low_i8x16_u(LiftoffRegister dst, 35951cb0ef41Sopenharmony_ci LiftoffRegister src1, 35961cb0ef41Sopenharmony_ci LiftoffRegister src2) { 35971cb0ef41Sopenharmony_ci I16x8ExtMulLow(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg, 35981cb0ef41Sopenharmony_ci /*is_signed=*/false); 35991cb0ef41Sopenharmony_ci} 36001cb0ef41Sopenharmony_ci 36011cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extmul_high_i8x16_s(LiftoffRegister dst, 36021cb0ef41Sopenharmony_ci LiftoffRegister src1, 36031cb0ef41Sopenharmony_ci LiftoffRegister src2) { 36041cb0ef41Sopenharmony_ci I16x8ExtMulHighS(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg); 36051cb0ef41Sopenharmony_ci} 36061cb0ef41Sopenharmony_ci 36071cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extmul_high_i8x16_u(LiftoffRegister dst, 36081cb0ef41Sopenharmony_ci LiftoffRegister src1, 36091cb0ef41Sopenharmony_ci LiftoffRegister src2) { 36101cb0ef41Sopenharmony_ci I16x8ExtMulHighU(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg); 36111cb0ef41Sopenharmony_ci} 36121cb0ef41Sopenharmony_ci 36131cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_q15mulr_sat_s(LiftoffRegister dst, 36141cb0ef41Sopenharmony_ci LiftoffRegister src1, 36151cb0ef41Sopenharmony_ci LiftoffRegister src2) { 36161cb0ef41Sopenharmony_ci I16x8Q15MulRSatS(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg); 36171cb0ef41Sopenharmony_ci} 36181cb0ef41Sopenharmony_ci 36191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_neg(LiftoffRegister dst, 36201cb0ef41Sopenharmony_ci LiftoffRegister src) { 36211cb0ef41Sopenharmony_ci if (dst.fp() == src.fp()) { 36221cb0ef41Sopenharmony_ci Pcmpeqd(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 36231cb0ef41Sopenharmony_ci Psignd(dst.fp(), liftoff::kScratchDoubleReg); 36241cb0ef41Sopenharmony_ci } else { 36251cb0ef41Sopenharmony_ci Pxor(dst.fp(), dst.fp()); 36261cb0ef41Sopenharmony_ci Psubd(dst.fp(), src.fp()); 36271cb0ef41Sopenharmony_ci } 36281cb0ef41Sopenharmony_ci} 36291cb0ef41Sopenharmony_ci 36301cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_alltrue(LiftoffRegister dst, 36311cb0ef41Sopenharmony_ci LiftoffRegister src) { 36321cb0ef41Sopenharmony_ci liftoff::EmitAllTrue<&TurboAssembler::Pcmpeqd>(this, dst, src); 36331cb0ef41Sopenharmony_ci} 36341cb0ef41Sopenharmony_ci 36351cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_bitmask(LiftoffRegister dst, 36361cb0ef41Sopenharmony_ci LiftoffRegister src) { 36371cb0ef41Sopenharmony_ci Movmskps(dst.gp(), src.fp()); 36381cb0ef41Sopenharmony_ci} 36391cb0ef41Sopenharmony_ci 36401cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs, 36411cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36421cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpslld, &Assembler::pslld, 5>(this, dst, 36431cb0ef41Sopenharmony_ci lhs, rhs); 36441cb0ef41Sopenharmony_ci} 36451cb0ef41Sopenharmony_ci 36461cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs, 36471cb0ef41Sopenharmony_ci int32_t rhs) { 36481cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpslld, &Assembler::pslld, 5>( 36491cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 36501cb0ef41Sopenharmony_ci} 36511cb0ef41Sopenharmony_ci 36521cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_shr_s(LiftoffRegister dst, 36531cb0ef41Sopenharmony_ci LiftoffRegister lhs, 36541cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36551cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsrad, &Assembler::psrad, 5>(this, dst, 36561cb0ef41Sopenharmony_ci lhs, rhs); 36571cb0ef41Sopenharmony_ci} 36581cb0ef41Sopenharmony_ci 36591cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_shri_s(LiftoffRegister dst, 36601cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 36611cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsrad, &Assembler::psrad, 5>( 36621cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 36631cb0ef41Sopenharmony_ci} 36641cb0ef41Sopenharmony_ci 36651cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_shr_u(LiftoffRegister dst, 36661cb0ef41Sopenharmony_ci LiftoffRegister lhs, 36671cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36681cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsrld, &Assembler::psrld, 5>(this, dst, 36691cb0ef41Sopenharmony_ci lhs, rhs); 36701cb0ef41Sopenharmony_ci} 36711cb0ef41Sopenharmony_ci 36721cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_shri_u(LiftoffRegister dst, 36731cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 36741cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsrld, &Assembler::psrld, 5>( 36751cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 36761cb0ef41Sopenharmony_ci} 36771cb0ef41Sopenharmony_ci 36781cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs, 36791cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36801cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddd, &Assembler::paddd>( 36811cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 36821cb0ef41Sopenharmony_ci} 36831cb0ef41Sopenharmony_ci 36841cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, 36851cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36861cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubd, &Assembler::psubd>( 36871cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 36881cb0ef41Sopenharmony_ci} 36891cb0ef41Sopenharmony_ci 36901cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, 36911cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36921cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmulld, &Assembler::pmulld>( 36931cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 36941cb0ef41Sopenharmony_ci} 36951cb0ef41Sopenharmony_ci 36961cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_min_s(LiftoffRegister dst, 36971cb0ef41Sopenharmony_ci LiftoffRegister lhs, 36981cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 36991cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminsd, &Assembler::pminsd>( 37001cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 37011cb0ef41Sopenharmony_ci} 37021cb0ef41Sopenharmony_ci 37031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_min_u(LiftoffRegister dst, 37041cb0ef41Sopenharmony_ci LiftoffRegister lhs, 37051cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 37061cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpminud, &Assembler::pminud>( 37071cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 37081cb0ef41Sopenharmony_ci} 37091cb0ef41Sopenharmony_ci 37101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_max_s(LiftoffRegister dst, 37111cb0ef41Sopenharmony_ci LiftoffRegister lhs, 37121cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 37131cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxsd, &Assembler::pmaxsd>( 37141cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 37151cb0ef41Sopenharmony_ci} 37161cb0ef41Sopenharmony_ci 37171cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_max_u(LiftoffRegister dst, 37181cb0ef41Sopenharmony_ci LiftoffRegister lhs, 37191cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 37201cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaxud, &Assembler::pmaxud>( 37211cb0ef41Sopenharmony_ci this, dst, lhs, rhs, base::Optional<CpuFeature>(SSE4_1)); 37221cb0ef41Sopenharmony_ci} 37231cb0ef41Sopenharmony_ci 37241cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_dot_i16x8_s(LiftoffRegister dst, 37251cb0ef41Sopenharmony_ci LiftoffRegister lhs, 37261cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 37271cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpmaddwd, &Assembler::pmaddwd>( 37281cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 37291cb0ef41Sopenharmony_ci} 37301cb0ef41Sopenharmony_ci 37311cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extadd_pairwise_i16x8_s(LiftoffRegister dst, 37321cb0ef41Sopenharmony_ci LiftoffRegister src) { 37331cb0ef41Sopenharmony_ci I32x4ExtAddPairwiseI16x8S(dst.fp(), src.fp(), 37341cb0ef41Sopenharmony_ci GetUnusedRegister(kGpReg, {}).gp()); 37351cb0ef41Sopenharmony_ci} 37361cb0ef41Sopenharmony_ci 37371cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extadd_pairwise_i16x8_u(LiftoffRegister dst, 37381cb0ef41Sopenharmony_ci LiftoffRegister src) { 37391cb0ef41Sopenharmony_ci I32x4ExtAddPairwiseI16x8U(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 37401cb0ef41Sopenharmony_ci} 37411cb0ef41Sopenharmony_ci 37421cb0ef41Sopenharmony_cinamespace liftoff { 37431cb0ef41Sopenharmony_ci// Helper function to check for register aliasing, AVX support, and moves 37441cb0ef41Sopenharmony_ci// registers around before calling the actual macro-assembler function. 37451cb0ef41Sopenharmony_ciinline void I32x4ExtMulHelper(LiftoffAssembler* assm, XMMRegister dst, 37461cb0ef41Sopenharmony_ci XMMRegister src1, XMMRegister src2, bool low, 37471cb0ef41Sopenharmony_ci bool is_signed) { 37481cb0ef41Sopenharmony_ci // I32x4ExtMul requires dst == src1 if AVX is not supported. 37491cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX) || dst == src1) { 37501cb0ef41Sopenharmony_ci assm->I32x4ExtMul(dst, src1, src2, liftoff::kScratchDoubleReg, low, 37511cb0ef41Sopenharmony_ci is_signed); 37521cb0ef41Sopenharmony_ci } else if (dst != src2) { 37531cb0ef41Sopenharmony_ci // dst != src1 && dst != src2 37541cb0ef41Sopenharmony_ci assm->movaps(dst, src1); 37551cb0ef41Sopenharmony_ci assm->I32x4ExtMul(dst, dst, src2, liftoff::kScratchDoubleReg, low, 37561cb0ef41Sopenharmony_ci is_signed); 37571cb0ef41Sopenharmony_ci } else { 37581cb0ef41Sopenharmony_ci // dst == src2 37591cb0ef41Sopenharmony_ci // Extended multiplication is commutative, 37601cb0ef41Sopenharmony_ci assm->movaps(dst, src2); 37611cb0ef41Sopenharmony_ci assm->I32x4ExtMul(dst, dst, src1, liftoff::kScratchDoubleReg, low, 37621cb0ef41Sopenharmony_ci is_signed); 37631cb0ef41Sopenharmony_ci } 37641cb0ef41Sopenharmony_ci} 37651cb0ef41Sopenharmony_ci} // namespace liftoff 37661cb0ef41Sopenharmony_ci 37671cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extmul_low_i16x8_s(LiftoffRegister dst, 37681cb0ef41Sopenharmony_ci LiftoffRegister src1, 37691cb0ef41Sopenharmony_ci LiftoffRegister src2) { 37701cb0ef41Sopenharmony_ci liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(), /*low=*/true, 37711cb0ef41Sopenharmony_ci /*is_signed=*/true); 37721cb0ef41Sopenharmony_ci} 37731cb0ef41Sopenharmony_ci 37741cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extmul_low_i16x8_u(LiftoffRegister dst, 37751cb0ef41Sopenharmony_ci LiftoffRegister src1, 37761cb0ef41Sopenharmony_ci LiftoffRegister src2) { 37771cb0ef41Sopenharmony_ci liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(), /*low=*/true, 37781cb0ef41Sopenharmony_ci /*is_signed=*/false); 37791cb0ef41Sopenharmony_ci} 37801cb0ef41Sopenharmony_ci 37811cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extmul_high_i16x8_s(LiftoffRegister dst, 37821cb0ef41Sopenharmony_ci LiftoffRegister src1, 37831cb0ef41Sopenharmony_ci LiftoffRegister src2) { 37841cb0ef41Sopenharmony_ci liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(), 37851cb0ef41Sopenharmony_ci /*low=*/false, 37861cb0ef41Sopenharmony_ci /*is_signed=*/true); 37871cb0ef41Sopenharmony_ci} 37881cb0ef41Sopenharmony_ci 37891cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extmul_high_i16x8_u(LiftoffRegister dst, 37901cb0ef41Sopenharmony_ci LiftoffRegister src1, 37911cb0ef41Sopenharmony_ci LiftoffRegister src2) { 37921cb0ef41Sopenharmony_ci liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(), 37931cb0ef41Sopenharmony_ci /*low=*/false, 37941cb0ef41Sopenharmony_ci /*is_signed=*/false); 37951cb0ef41Sopenharmony_ci} 37961cb0ef41Sopenharmony_ci 37971cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_neg(LiftoffRegister dst, 37981cb0ef41Sopenharmony_ci LiftoffRegister src) { 37991cb0ef41Sopenharmony_ci I64x2Neg(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 38001cb0ef41Sopenharmony_ci} 38011cb0ef41Sopenharmony_ci 38021cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_alltrue(LiftoffRegister dst, 38031cb0ef41Sopenharmony_ci LiftoffRegister src) { 38041cb0ef41Sopenharmony_ci liftoff::EmitAllTrue<&TurboAssembler::Pcmpeqq>(this, dst, src, SSE4_1); 38051cb0ef41Sopenharmony_ci} 38061cb0ef41Sopenharmony_ci 38071cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs, 38081cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 38091cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsllq, &Assembler::psllq, 6>(this, dst, 38101cb0ef41Sopenharmony_ci lhs, rhs); 38111cb0ef41Sopenharmony_ci} 38121cb0ef41Sopenharmony_ci 38131cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs, 38141cb0ef41Sopenharmony_ci int32_t rhs) { 38151cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsllq, &Assembler::psllq, 6>( 38161cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 38171cb0ef41Sopenharmony_ci} 38181cb0ef41Sopenharmony_ci 38191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_shr_s(LiftoffRegister dst, 38201cb0ef41Sopenharmony_ci LiftoffRegister lhs, 38211cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 38221cb0ef41Sopenharmony_ci XMMRegister tmp = 38231cb0ef41Sopenharmony_ci GetUnusedRegister(RegClass::kFpReg, LiftoffRegList{dst, lhs}).fp(); 38241cb0ef41Sopenharmony_ci Register scratch = 38251cb0ef41Sopenharmony_ci GetUnusedRegister(RegClass::kGpReg, LiftoffRegList{rhs}).gp(); 38261cb0ef41Sopenharmony_ci 38271cb0ef41Sopenharmony_ci I64x2ShrS(dst.fp(), lhs.fp(), rhs.gp(), liftoff::kScratchDoubleReg, tmp, 38281cb0ef41Sopenharmony_ci scratch); 38291cb0ef41Sopenharmony_ci} 38301cb0ef41Sopenharmony_ci 38311cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_shri_s(LiftoffRegister dst, 38321cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 38331cb0ef41Sopenharmony_ci I64x2ShrS(dst.fp(), lhs.fp(), rhs & 0x3F, liftoff::kScratchDoubleReg); 38341cb0ef41Sopenharmony_ci} 38351cb0ef41Sopenharmony_ci 38361cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_shr_u(LiftoffRegister dst, 38371cb0ef41Sopenharmony_ci LiftoffRegister lhs, 38381cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 38391cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOp<&Assembler::vpsrlq, &Assembler::psrlq, 6>(this, dst, 38401cb0ef41Sopenharmony_ci lhs, rhs); 38411cb0ef41Sopenharmony_ci} 38421cb0ef41Sopenharmony_ci 38431cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_shri_u(LiftoffRegister dst, 38441cb0ef41Sopenharmony_ci LiftoffRegister lhs, int32_t rhs) { 38451cb0ef41Sopenharmony_ci liftoff::EmitSimdShiftOpImm<&Assembler::vpsrlq, &Assembler::psrlq, 6>( 38461cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 38471cb0ef41Sopenharmony_ci} 38481cb0ef41Sopenharmony_ci 38491cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs, 38501cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 38511cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpaddq, &Assembler::paddq>( 38521cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 38531cb0ef41Sopenharmony_ci} 38541cb0ef41Sopenharmony_ci 38551cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, 38561cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 38571cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubq, &Assembler::psubq>( 38581cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 38591cb0ef41Sopenharmony_ci} 38601cb0ef41Sopenharmony_ci 38611cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, 38621cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 38631cb0ef41Sopenharmony_ci static constexpr RegClass tmp_rc = reg_class_for(kS128); 38641cb0ef41Sopenharmony_ci LiftoffRegister tmp1 = 38651cb0ef41Sopenharmony_ci GetUnusedRegister(tmp_rc, LiftoffRegList{dst, lhs, rhs}); 38661cb0ef41Sopenharmony_ci LiftoffRegister tmp2 = 38671cb0ef41Sopenharmony_ci GetUnusedRegister(tmp_rc, LiftoffRegList{dst, lhs, rhs, tmp1}); 38681cb0ef41Sopenharmony_ci I64x2Mul(dst.fp(), lhs.fp(), rhs.fp(), tmp1.fp(), tmp2.fp()); 38691cb0ef41Sopenharmony_ci} 38701cb0ef41Sopenharmony_ci 38711cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_extmul_low_i32x4_s(LiftoffRegister dst, 38721cb0ef41Sopenharmony_ci LiftoffRegister src1, 38731cb0ef41Sopenharmony_ci LiftoffRegister src2) { 38741cb0ef41Sopenharmony_ci I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg, 38751cb0ef41Sopenharmony_ci /*low=*/true, /*is_signed=*/true); 38761cb0ef41Sopenharmony_ci} 38771cb0ef41Sopenharmony_ci 38781cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_extmul_low_i32x4_u(LiftoffRegister dst, 38791cb0ef41Sopenharmony_ci LiftoffRegister src1, 38801cb0ef41Sopenharmony_ci LiftoffRegister src2) { 38811cb0ef41Sopenharmony_ci I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg, 38821cb0ef41Sopenharmony_ci /*low=*/true, /*is_signed=*/false); 38831cb0ef41Sopenharmony_ci} 38841cb0ef41Sopenharmony_ci 38851cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_extmul_high_i32x4_s(LiftoffRegister dst, 38861cb0ef41Sopenharmony_ci LiftoffRegister src1, 38871cb0ef41Sopenharmony_ci LiftoffRegister src2) { 38881cb0ef41Sopenharmony_ci I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg, 38891cb0ef41Sopenharmony_ci /*low=*/false, /*is_signed=*/true); 38901cb0ef41Sopenharmony_ci} 38911cb0ef41Sopenharmony_ci 38921cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_extmul_high_i32x4_u(LiftoffRegister dst, 38931cb0ef41Sopenharmony_ci LiftoffRegister src1, 38941cb0ef41Sopenharmony_ci LiftoffRegister src2) { 38951cb0ef41Sopenharmony_ci I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), liftoff::kScratchDoubleReg, 38961cb0ef41Sopenharmony_ci /*low=*/false, /*is_signed=*/false); 38971cb0ef41Sopenharmony_ci} 38981cb0ef41Sopenharmony_ci 38991cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_bitmask(LiftoffRegister dst, 39001cb0ef41Sopenharmony_ci LiftoffRegister src) { 39011cb0ef41Sopenharmony_ci Movmskpd(dst.gp(), src.fp()); 39021cb0ef41Sopenharmony_ci} 39031cb0ef41Sopenharmony_ci 39041cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_sconvert_i32x4_low(LiftoffRegister dst, 39051cb0ef41Sopenharmony_ci LiftoffRegister src) { 39061cb0ef41Sopenharmony_ci Pmovsxdq(dst.fp(), src.fp()); 39071cb0ef41Sopenharmony_ci} 39081cb0ef41Sopenharmony_ci 39091cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_sconvert_i32x4_high(LiftoffRegister dst, 39101cb0ef41Sopenharmony_ci LiftoffRegister src) { 39111cb0ef41Sopenharmony_ci I64x2SConvertI32x4High(dst.fp(), src.fp()); 39121cb0ef41Sopenharmony_ci} 39131cb0ef41Sopenharmony_ci 39141cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_uconvert_i32x4_low(LiftoffRegister dst, 39151cb0ef41Sopenharmony_ci LiftoffRegister src) { 39161cb0ef41Sopenharmony_ci Pmovzxdq(dst.fp(), src.fp()); 39171cb0ef41Sopenharmony_ci} 39181cb0ef41Sopenharmony_ci 39191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_uconvert_i32x4_high(LiftoffRegister dst, 39201cb0ef41Sopenharmony_ci LiftoffRegister src) { 39211cb0ef41Sopenharmony_ci I64x2UConvertI32x4High(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 39221cb0ef41Sopenharmony_ci} 39231cb0ef41Sopenharmony_ci 39241cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_abs(LiftoffRegister dst, 39251cb0ef41Sopenharmony_ci LiftoffRegister src) { 39261cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 39271cb0ef41Sopenharmony_ci Absps(dst.fp(), src.fp(), tmp); 39281cb0ef41Sopenharmony_ci} 39291cb0ef41Sopenharmony_ci 39301cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_neg(LiftoffRegister dst, 39311cb0ef41Sopenharmony_ci LiftoffRegister src) { 39321cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 39331cb0ef41Sopenharmony_ci Negps(dst.fp(), src.fp(), tmp); 39341cb0ef41Sopenharmony_ci} 39351cb0ef41Sopenharmony_ci 39361cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_sqrt(LiftoffRegister dst, 39371cb0ef41Sopenharmony_ci LiftoffRegister src) { 39381cb0ef41Sopenharmony_ci Sqrtps(dst.fp(), src.fp()); 39391cb0ef41Sopenharmony_ci} 39401cb0ef41Sopenharmony_ci 39411cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32x4_ceil(LiftoffRegister dst, 39421cb0ef41Sopenharmony_ci LiftoffRegister src) { 39431cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 39441cb0ef41Sopenharmony_ci Roundps(dst.fp(), src.fp(), kRoundUp); 39451cb0ef41Sopenharmony_ci return true; 39461cb0ef41Sopenharmony_ci} 39471cb0ef41Sopenharmony_ci 39481cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32x4_floor(LiftoffRegister dst, 39491cb0ef41Sopenharmony_ci LiftoffRegister src) { 39501cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 39511cb0ef41Sopenharmony_ci Roundps(dst.fp(), src.fp(), kRoundDown); 39521cb0ef41Sopenharmony_ci return true; 39531cb0ef41Sopenharmony_ci} 39541cb0ef41Sopenharmony_ci 39551cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32x4_trunc(LiftoffRegister dst, 39561cb0ef41Sopenharmony_ci LiftoffRegister src) { 39571cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 39581cb0ef41Sopenharmony_ci Roundps(dst.fp(), src.fp(), kRoundToZero); 39591cb0ef41Sopenharmony_ci return true; 39601cb0ef41Sopenharmony_ci} 39611cb0ef41Sopenharmony_ci 39621cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f32x4_nearest_int(LiftoffRegister dst, 39631cb0ef41Sopenharmony_ci LiftoffRegister src) { 39641cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 39651cb0ef41Sopenharmony_ci Roundps(dst.fp(), src.fp(), kRoundToNearest); 39661cb0ef41Sopenharmony_ci return true; 39671cb0ef41Sopenharmony_ci} 39681cb0ef41Sopenharmony_ci 39691cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs, 39701cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 39711cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vaddps, &Assembler::addps>( 39721cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 39731cb0ef41Sopenharmony_ci} 39741cb0ef41Sopenharmony_ci 39751cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, 39761cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 39771cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vsubps, &Assembler::subps>( 39781cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 39791cb0ef41Sopenharmony_ci} 39801cb0ef41Sopenharmony_ci 39811cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, 39821cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 39831cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vmulps, &Assembler::mulps>( 39841cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 39851cb0ef41Sopenharmony_ci} 39861cb0ef41Sopenharmony_ci 39871cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs, 39881cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 39891cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vdivps, &Assembler::divps>( 39901cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 39911cb0ef41Sopenharmony_ci} 39921cb0ef41Sopenharmony_ci 39931cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs, 39941cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 39951cb0ef41Sopenharmony_ci F32x4Min(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 39961cb0ef41Sopenharmony_ci} 39971cb0ef41Sopenharmony_ci 39981cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs, 39991cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40001cb0ef41Sopenharmony_ci F32x4Max(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 40011cb0ef41Sopenharmony_ci} 40021cb0ef41Sopenharmony_ci 40031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs, 40041cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40051cb0ef41Sopenharmony_ci // Due to the way minps works, pmin(a, b) = minps(b, a). 40061cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vminps, &Assembler::minps>( 40071cb0ef41Sopenharmony_ci this, dst, rhs, lhs); 40081cb0ef41Sopenharmony_ci} 40091cb0ef41Sopenharmony_ci 40101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs, 40111cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40121cb0ef41Sopenharmony_ci // Due to the way maxps works, pmax(a, b) = maxps(b, a). 40131cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vmaxps, &Assembler::maxps>( 40141cb0ef41Sopenharmony_ci this, dst, rhs, lhs); 40151cb0ef41Sopenharmony_ci} 40161cb0ef41Sopenharmony_ci 40171cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_abs(LiftoffRegister dst, 40181cb0ef41Sopenharmony_ci LiftoffRegister src) { 40191cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 40201cb0ef41Sopenharmony_ci Abspd(dst.fp(), src.fp(), tmp); 40211cb0ef41Sopenharmony_ci} 40221cb0ef41Sopenharmony_ci 40231cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_neg(LiftoffRegister dst, 40241cb0ef41Sopenharmony_ci LiftoffRegister src) { 40251cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 40261cb0ef41Sopenharmony_ci Negpd(dst.fp(), src.fp(), tmp); 40271cb0ef41Sopenharmony_ci} 40281cb0ef41Sopenharmony_ci 40291cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_sqrt(LiftoffRegister dst, 40301cb0ef41Sopenharmony_ci LiftoffRegister src) { 40311cb0ef41Sopenharmony_ci Sqrtpd(dst.fp(), src.fp()); 40321cb0ef41Sopenharmony_ci} 40331cb0ef41Sopenharmony_ci 40341cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64x2_ceil(LiftoffRegister dst, 40351cb0ef41Sopenharmony_ci LiftoffRegister src) { 40361cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 40371cb0ef41Sopenharmony_ci Roundpd(dst.fp(), src.fp(), kRoundUp); 40381cb0ef41Sopenharmony_ci return true; 40391cb0ef41Sopenharmony_ci} 40401cb0ef41Sopenharmony_ci 40411cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64x2_floor(LiftoffRegister dst, 40421cb0ef41Sopenharmony_ci LiftoffRegister src) { 40431cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 40441cb0ef41Sopenharmony_ci Roundpd(dst.fp(), src.fp(), kRoundDown); 40451cb0ef41Sopenharmony_ci return true; 40461cb0ef41Sopenharmony_ci} 40471cb0ef41Sopenharmony_ci 40481cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64x2_trunc(LiftoffRegister dst, 40491cb0ef41Sopenharmony_ci LiftoffRegister src) { 40501cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 40511cb0ef41Sopenharmony_ci Roundpd(dst.fp(), src.fp(), kRoundToZero); 40521cb0ef41Sopenharmony_ci return true; 40531cb0ef41Sopenharmony_ci} 40541cb0ef41Sopenharmony_ci 40551cb0ef41Sopenharmony_cibool LiftoffAssembler::emit_f64x2_nearest_int(LiftoffRegister dst, 40561cb0ef41Sopenharmony_ci LiftoffRegister src) { 40571cb0ef41Sopenharmony_ci DCHECK(CpuFeatures::IsSupported(SSE4_1)); 40581cb0ef41Sopenharmony_ci Roundpd(dst.fp(), src.fp(), kRoundToNearest); 40591cb0ef41Sopenharmony_ci return true; 40601cb0ef41Sopenharmony_ci} 40611cb0ef41Sopenharmony_ci 40621cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs, 40631cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40641cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vaddpd, &Assembler::addpd>( 40651cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 40661cb0ef41Sopenharmony_ci} 40671cb0ef41Sopenharmony_ci 40681cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, 40691cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40701cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vsubpd, &Assembler::subpd>( 40711cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 40721cb0ef41Sopenharmony_ci} 40731cb0ef41Sopenharmony_ci 40741cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, 40751cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40761cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vmulpd, &Assembler::mulpd>( 40771cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 40781cb0ef41Sopenharmony_ci} 40791cb0ef41Sopenharmony_ci 40801cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs, 40811cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40821cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vdivpd, &Assembler::divpd>( 40831cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 40841cb0ef41Sopenharmony_ci} 40851cb0ef41Sopenharmony_ci 40861cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs, 40871cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40881cb0ef41Sopenharmony_ci F64x2Min(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 40891cb0ef41Sopenharmony_ci} 40901cb0ef41Sopenharmony_ci 40911cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs, 40921cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40931cb0ef41Sopenharmony_ci F64x2Max(dst.fp(), lhs.fp(), rhs.fp(), liftoff::kScratchDoubleReg); 40941cb0ef41Sopenharmony_ci} 40951cb0ef41Sopenharmony_ci 40961cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs, 40971cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 40981cb0ef41Sopenharmony_ci // Due to the way minpd works, pmin(a, b) = minpd(b, a). 40991cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vminpd, &Assembler::minpd>( 41001cb0ef41Sopenharmony_ci this, dst, rhs, lhs); 41011cb0ef41Sopenharmony_ci} 41021cb0ef41Sopenharmony_ci 41031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs, 41041cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 41051cb0ef41Sopenharmony_ci // Due to the way maxpd works, pmax(a, b) = maxpd(b, a). 41061cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vmaxpd, &Assembler::maxpd>( 41071cb0ef41Sopenharmony_ci this, dst, rhs, lhs); 41081cb0ef41Sopenharmony_ci} 41091cb0ef41Sopenharmony_ci 41101cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_convert_low_i32x4_s(LiftoffRegister dst, 41111cb0ef41Sopenharmony_ci LiftoffRegister src) { 41121cb0ef41Sopenharmony_ci Cvtdq2pd(dst.fp(), src.fp()); 41131cb0ef41Sopenharmony_ci} 41141cb0ef41Sopenharmony_ci 41151cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_convert_low_i32x4_u(LiftoffRegister dst, 41161cb0ef41Sopenharmony_ci LiftoffRegister src) { 41171cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 41181cb0ef41Sopenharmony_ci F64x2ConvertLowI32x4U(dst.fp(), src.fp(), tmp); 41191cb0ef41Sopenharmony_ci} 41201cb0ef41Sopenharmony_ci 41211cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_promote_low_f32x4(LiftoffRegister dst, 41221cb0ef41Sopenharmony_ci LiftoffRegister src) { 41231cb0ef41Sopenharmony_ci Cvtps2pd(dst.fp(), src.fp()); 41241cb0ef41Sopenharmony_ci} 41251cb0ef41Sopenharmony_ci 41261cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_sconvert_f32x4(LiftoffRegister dst, 41271cb0ef41Sopenharmony_ci LiftoffRegister src) { 41281cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 41291cb0ef41Sopenharmony_ci I32x4SConvertF32x4(dst.fp(), src.fp(), liftoff::kScratchDoubleReg, tmp); 41301cb0ef41Sopenharmony_ci} 41311cb0ef41Sopenharmony_ci 41321cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_uconvert_f32x4(LiftoffRegister dst, 41331cb0ef41Sopenharmony_ci LiftoffRegister src) { 41341cb0ef41Sopenharmony_ci static constexpr RegClass tmp_rc = reg_class_for(kS128); 41351cb0ef41Sopenharmony_ci DoubleRegister tmp = GetUnusedRegister(tmp_rc, LiftoffRegList{dst, src}).fp(); 41361cb0ef41Sopenharmony_ci // NAN->0, negative->0. 41371cb0ef41Sopenharmony_ci Pxor(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 41381cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 41391cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 41401cb0ef41Sopenharmony_ci vmaxps(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 41411cb0ef41Sopenharmony_ci } else { 41421cb0ef41Sopenharmony_ci if (dst.fp() != src.fp()) movaps(dst.fp(), src.fp()); 41431cb0ef41Sopenharmony_ci maxps(dst.fp(), liftoff::kScratchDoubleReg); 41441cb0ef41Sopenharmony_ci } 41451cb0ef41Sopenharmony_ci // scratch: float representation of max_signed. 41461cb0ef41Sopenharmony_ci Pcmpeqd(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 41471cb0ef41Sopenharmony_ci Psrld(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg, 41481cb0ef41Sopenharmony_ci uint8_t{1}); // 0x7fffffff 41491cb0ef41Sopenharmony_ci Cvtdq2ps(liftoff::kScratchDoubleReg, 41501cb0ef41Sopenharmony_ci liftoff::kScratchDoubleReg); // 0x4f000000 41511cb0ef41Sopenharmony_ci // tmp: convert (src-max_signed). 41521cb0ef41Sopenharmony_ci // Set positive overflow lanes to 0x7FFFFFFF. 41531cb0ef41Sopenharmony_ci // Set negative lanes to 0. 41541cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 41551cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 41561cb0ef41Sopenharmony_ci vsubps(tmp, dst.fp(), liftoff::kScratchDoubleReg); 41571cb0ef41Sopenharmony_ci } else { 41581cb0ef41Sopenharmony_ci movaps(tmp, dst.fp()); 41591cb0ef41Sopenharmony_ci subps(tmp, liftoff::kScratchDoubleReg); 41601cb0ef41Sopenharmony_ci } 41611cb0ef41Sopenharmony_ci Cmpleps(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg, tmp); 41621cb0ef41Sopenharmony_ci Cvttps2dq(tmp, tmp); 41631cb0ef41Sopenharmony_ci Pxor(tmp, liftoff::kScratchDoubleReg); 41641cb0ef41Sopenharmony_ci Pxor(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); 41651cb0ef41Sopenharmony_ci Pmaxsd(tmp, tmp, liftoff::kScratchDoubleReg); 41661cb0ef41Sopenharmony_ci // Convert to int. Overflow lanes above max_signed will be 0x80000000. 41671cb0ef41Sopenharmony_ci Cvttps2dq(dst.fp(), dst.fp()); 41681cb0ef41Sopenharmony_ci // Add (src-max_signed) for overflow lanes. 41691cb0ef41Sopenharmony_ci Paddd(dst.fp(), dst.fp(), tmp); 41701cb0ef41Sopenharmony_ci} 41711cb0ef41Sopenharmony_ci 41721cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_sconvert_i32x4(LiftoffRegister dst, 41731cb0ef41Sopenharmony_ci LiftoffRegister src) { 41741cb0ef41Sopenharmony_ci Cvtdq2ps(dst.fp(), src.fp()); 41751cb0ef41Sopenharmony_ci} 41761cb0ef41Sopenharmony_ci 41771cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_uconvert_i32x4(LiftoffRegister dst, 41781cb0ef41Sopenharmony_ci LiftoffRegister src) { 41791cb0ef41Sopenharmony_ci Pxor(liftoff::kScratchDoubleReg, liftoff::kScratchDoubleReg); // Zeros. 41801cb0ef41Sopenharmony_ci Pblendw(liftoff::kScratchDoubleReg, src.fp(), 41811cb0ef41Sopenharmony_ci uint8_t{0x55}); // Get lo 16 bits. 41821cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 41831cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 41841cb0ef41Sopenharmony_ci vpsubd(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); // Get hi 16 bits. 41851cb0ef41Sopenharmony_ci } else { 41861cb0ef41Sopenharmony_ci if (dst.fp() != src.fp()) movaps(dst.fp(), src.fp()); 41871cb0ef41Sopenharmony_ci psubd(dst.fp(), liftoff::kScratchDoubleReg); 41881cb0ef41Sopenharmony_ci } 41891cb0ef41Sopenharmony_ci Cvtdq2ps(liftoff::kScratchDoubleReg, 41901cb0ef41Sopenharmony_ci liftoff::kScratchDoubleReg); // Convert lo exactly. 41911cb0ef41Sopenharmony_ci Psrld(dst.fp(), dst.fp(), byte{1}); // Divide by 2 to get in unsigned range. 41921cb0ef41Sopenharmony_ci Cvtdq2ps(dst.fp(), dst.fp()); // Convert hi, exactly. 41931cb0ef41Sopenharmony_ci Addps(dst.fp(), dst.fp(), dst.fp()); // Double hi, exactly. 41941cb0ef41Sopenharmony_ci Addps(dst.fp(), dst.fp(), 41951cb0ef41Sopenharmony_ci liftoff::kScratchDoubleReg); // Add hi and lo, may round. 41961cb0ef41Sopenharmony_ci} 41971cb0ef41Sopenharmony_ci 41981cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_demote_f64x2_zero(LiftoffRegister dst, 41991cb0ef41Sopenharmony_ci LiftoffRegister src) { 42001cb0ef41Sopenharmony_ci Cvtpd2ps(dst.fp(), src.fp()); 42011cb0ef41Sopenharmony_ci} 42021cb0ef41Sopenharmony_ci 42031cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_sconvert_i16x8(LiftoffRegister dst, 42041cb0ef41Sopenharmony_ci LiftoffRegister lhs, 42051cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 42061cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpacksswb, 42071cb0ef41Sopenharmony_ci &Assembler::packsswb>(this, dst, lhs, 42081cb0ef41Sopenharmony_ci rhs); 42091cb0ef41Sopenharmony_ci} 42101cb0ef41Sopenharmony_ci 42111cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_uconvert_i16x8(LiftoffRegister dst, 42121cb0ef41Sopenharmony_ci LiftoffRegister lhs, 42131cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 42141cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpackuswb, 42151cb0ef41Sopenharmony_ci &Assembler::packuswb>(this, dst, lhs, 42161cb0ef41Sopenharmony_ci rhs); 42171cb0ef41Sopenharmony_ci} 42181cb0ef41Sopenharmony_ci 42191cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_sconvert_i32x4(LiftoffRegister dst, 42201cb0ef41Sopenharmony_ci LiftoffRegister lhs, 42211cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 42221cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpackssdw, 42231cb0ef41Sopenharmony_ci &Assembler::packssdw>(this, dst, lhs, 42241cb0ef41Sopenharmony_ci rhs); 42251cb0ef41Sopenharmony_ci} 42261cb0ef41Sopenharmony_ci 42271cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_uconvert_i32x4(LiftoffRegister dst, 42281cb0ef41Sopenharmony_ci LiftoffRegister lhs, 42291cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 42301cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpackusdw, 42311cb0ef41Sopenharmony_ci &Assembler::packusdw>(this, dst, lhs, 42321cb0ef41Sopenharmony_ci rhs, SSE4_1); 42331cb0ef41Sopenharmony_ci} 42341cb0ef41Sopenharmony_ci 42351cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_sconvert_i8x16_low(LiftoffRegister dst, 42361cb0ef41Sopenharmony_ci LiftoffRegister src) { 42371cb0ef41Sopenharmony_ci Pmovsxbw(dst.fp(), src.fp()); 42381cb0ef41Sopenharmony_ci} 42391cb0ef41Sopenharmony_ci 42401cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_sconvert_i8x16_high(LiftoffRegister dst, 42411cb0ef41Sopenharmony_ci LiftoffRegister src) { 42421cb0ef41Sopenharmony_ci I16x8SConvertI8x16High(dst.fp(), src.fp()); 42431cb0ef41Sopenharmony_ci} 42441cb0ef41Sopenharmony_ci 42451cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_uconvert_i8x16_low(LiftoffRegister dst, 42461cb0ef41Sopenharmony_ci LiftoffRegister src) { 42471cb0ef41Sopenharmony_ci Pmovzxbw(dst.fp(), src.fp()); 42481cb0ef41Sopenharmony_ci} 42491cb0ef41Sopenharmony_ci 42501cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_uconvert_i8x16_high(LiftoffRegister dst, 42511cb0ef41Sopenharmony_ci LiftoffRegister src) { 42521cb0ef41Sopenharmony_ci I16x8UConvertI8x16High(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 42531cb0ef41Sopenharmony_ci} 42541cb0ef41Sopenharmony_ci 42551cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_sconvert_i16x8_low(LiftoffRegister dst, 42561cb0ef41Sopenharmony_ci LiftoffRegister src) { 42571cb0ef41Sopenharmony_ci Pmovsxwd(dst.fp(), src.fp()); 42581cb0ef41Sopenharmony_ci} 42591cb0ef41Sopenharmony_ci 42601cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_sconvert_i16x8_high(LiftoffRegister dst, 42611cb0ef41Sopenharmony_ci LiftoffRegister src) { 42621cb0ef41Sopenharmony_ci I32x4SConvertI16x8High(dst.fp(), src.fp()); 42631cb0ef41Sopenharmony_ci} 42641cb0ef41Sopenharmony_ci 42651cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_uconvert_i16x8_low(LiftoffRegister dst, 42661cb0ef41Sopenharmony_ci LiftoffRegister src) { 42671cb0ef41Sopenharmony_ci Pmovzxwd(dst.fp(), src.fp()); 42681cb0ef41Sopenharmony_ci} 42691cb0ef41Sopenharmony_ci 42701cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_uconvert_i16x8_high(LiftoffRegister dst, 42711cb0ef41Sopenharmony_ci LiftoffRegister src) { 42721cb0ef41Sopenharmony_ci I32x4UConvertI16x8High(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 42731cb0ef41Sopenharmony_ci} 42741cb0ef41Sopenharmony_ci 42751cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_trunc_sat_f64x2_s_zero(LiftoffRegister dst, 42761cb0ef41Sopenharmony_ci LiftoffRegister src) { 42771cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 42781cb0ef41Sopenharmony_ci I32x4TruncSatF64x2SZero(dst.fp(), src.fp(), liftoff::kScratchDoubleReg, tmp); 42791cb0ef41Sopenharmony_ci} 42801cb0ef41Sopenharmony_ci 42811cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_trunc_sat_f64x2_u_zero(LiftoffRegister dst, 42821cb0ef41Sopenharmony_ci LiftoffRegister src) { 42831cb0ef41Sopenharmony_ci Register tmp = GetUnusedRegister(kGpReg, {}).gp(); 42841cb0ef41Sopenharmony_ci I32x4TruncSatF64x2UZero(dst.fp(), src.fp(), liftoff::kScratchDoubleReg, tmp); 42851cb0ef41Sopenharmony_ci} 42861cb0ef41Sopenharmony_ci 42871cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_and_not(LiftoffRegister dst, 42881cb0ef41Sopenharmony_ci LiftoffRegister lhs, 42891cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 42901cb0ef41Sopenharmony_ci liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vandnps, &Assembler::andnps>( 42911cb0ef41Sopenharmony_ci this, dst, rhs, lhs); 42921cb0ef41Sopenharmony_ci} 42931cb0ef41Sopenharmony_ci 42941cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_rounding_average_u(LiftoffRegister dst, 42951cb0ef41Sopenharmony_ci LiftoffRegister lhs, 42961cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 42971cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpavgb, &Assembler::pavgb>( 42981cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 42991cb0ef41Sopenharmony_ci} 43001cb0ef41Sopenharmony_ci 43011cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_rounding_average_u(LiftoffRegister dst, 43021cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43031cb0ef41Sopenharmony_ci LiftoffRegister rhs) { 43041cb0ef41Sopenharmony_ci liftoff::EmitSimdCommutativeBinOp<&Assembler::vpavgw, &Assembler::pavgw>( 43051cb0ef41Sopenharmony_ci this, dst, lhs, rhs); 43061cb0ef41Sopenharmony_ci} 43071cb0ef41Sopenharmony_ci 43081cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_abs(LiftoffRegister dst, 43091cb0ef41Sopenharmony_ci LiftoffRegister src) { 43101cb0ef41Sopenharmony_ci Pabsb(dst.fp(), src.fp()); 43111cb0ef41Sopenharmony_ci} 43121cb0ef41Sopenharmony_ci 43131cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_abs(LiftoffRegister dst, 43141cb0ef41Sopenharmony_ci LiftoffRegister src) { 43151cb0ef41Sopenharmony_ci Pabsw(dst.fp(), src.fp()); 43161cb0ef41Sopenharmony_ci} 43171cb0ef41Sopenharmony_ci 43181cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_abs(LiftoffRegister dst, 43191cb0ef41Sopenharmony_ci LiftoffRegister src) { 43201cb0ef41Sopenharmony_ci Pabsd(dst.fp(), src.fp()); 43211cb0ef41Sopenharmony_ci} 43221cb0ef41Sopenharmony_ci 43231cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_abs(LiftoffRegister dst, 43241cb0ef41Sopenharmony_ci LiftoffRegister src) { 43251cb0ef41Sopenharmony_ci I64x2Abs(dst.fp(), src.fp(), liftoff::kScratchDoubleReg); 43261cb0ef41Sopenharmony_ci} 43271cb0ef41Sopenharmony_ci 43281cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_extract_lane_s(LiftoffRegister dst, 43291cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43301cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43311cb0ef41Sopenharmony_ci Register byte_reg = liftoff::GetTmpByteRegister(this, dst.gp()); 43321cb0ef41Sopenharmony_ci Pextrb(byte_reg, lhs.fp(), imm_lane_idx); 43331cb0ef41Sopenharmony_ci movsx_b(dst.gp(), byte_reg); 43341cb0ef41Sopenharmony_ci} 43351cb0ef41Sopenharmony_ci 43361cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_extract_lane_u(LiftoffRegister dst, 43371cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43381cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43391cb0ef41Sopenharmony_ci Pextrb(dst.gp(), lhs.fp(), imm_lane_idx); 43401cb0ef41Sopenharmony_ci} 43411cb0ef41Sopenharmony_ci 43421cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extract_lane_s(LiftoffRegister dst, 43431cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43441cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43451cb0ef41Sopenharmony_ci Pextrw(dst.gp(), lhs.fp(), imm_lane_idx); 43461cb0ef41Sopenharmony_ci movsx_w(dst.gp(), dst.gp()); 43471cb0ef41Sopenharmony_ci} 43481cb0ef41Sopenharmony_ci 43491cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_extract_lane_u(LiftoffRegister dst, 43501cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43511cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43521cb0ef41Sopenharmony_ci Pextrw(dst.gp(), lhs.fp(), imm_lane_idx); 43531cb0ef41Sopenharmony_ci} 43541cb0ef41Sopenharmony_ci 43551cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_extract_lane(LiftoffRegister dst, 43561cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43571cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43581cb0ef41Sopenharmony_ci Pextrd(dst.gp(), lhs.fp(), imm_lane_idx); 43591cb0ef41Sopenharmony_ci} 43601cb0ef41Sopenharmony_ci 43611cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_extract_lane(LiftoffRegister dst, 43621cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43631cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43641cb0ef41Sopenharmony_ci Pextrd(dst.low_gp(), lhs.fp(), imm_lane_idx * 2); 43651cb0ef41Sopenharmony_ci Pextrd(dst.high_gp(), lhs.fp(), imm_lane_idx * 2 + 1); 43661cb0ef41Sopenharmony_ci} 43671cb0ef41Sopenharmony_ci 43681cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_extract_lane(LiftoffRegister dst, 43691cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43701cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43711cb0ef41Sopenharmony_ci F32x4ExtractLane(dst.fp(), lhs.fp(), imm_lane_idx); 43721cb0ef41Sopenharmony_ci} 43731cb0ef41Sopenharmony_ci 43741cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_extract_lane(LiftoffRegister dst, 43751cb0ef41Sopenharmony_ci LiftoffRegister lhs, 43761cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43771cb0ef41Sopenharmony_ci F64x2ExtractLane(dst.fp(), lhs.fp(), imm_lane_idx); 43781cb0ef41Sopenharmony_ci} 43791cb0ef41Sopenharmony_ci 43801cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i8x16_replace_lane(LiftoffRegister dst, 43811cb0ef41Sopenharmony_ci LiftoffRegister src1, 43821cb0ef41Sopenharmony_ci LiftoffRegister src2, 43831cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43841cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 43851cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 43861cb0ef41Sopenharmony_ci vpinsrb(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx); 43871cb0ef41Sopenharmony_ci } else { 43881cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, SSE4_1); 43891cb0ef41Sopenharmony_ci if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp()); 43901cb0ef41Sopenharmony_ci pinsrb(dst.fp(), src2.gp(), imm_lane_idx); 43911cb0ef41Sopenharmony_ci } 43921cb0ef41Sopenharmony_ci} 43931cb0ef41Sopenharmony_ci 43941cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i16x8_replace_lane(LiftoffRegister dst, 43951cb0ef41Sopenharmony_ci LiftoffRegister src1, 43961cb0ef41Sopenharmony_ci LiftoffRegister src2, 43971cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 43981cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 43991cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 44001cb0ef41Sopenharmony_ci vpinsrw(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx); 44011cb0ef41Sopenharmony_ci } else { 44021cb0ef41Sopenharmony_ci if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp()); 44031cb0ef41Sopenharmony_ci pinsrw(dst.fp(), src2.gp(), imm_lane_idx); 44041cb0ef41Sopenharmony_ci } 44051cb0ef41Sopenharmony_ci} 44061cb0ef41Sopenharmony_ci 44071cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i32x4_replace_lane(LiftoffRegister dst, 44081cb0ef41Sopenharmony_ci LiftoffRegister src1, 44091cb0ef41Sopenharmony_ci LiftoffRegister src2, 44101cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 44111cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 44121cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 44131cb0ef41Sopenharmony_ci vpinsrd(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx); 44141cb0ef41Sopenharmony_ci } else { 44151cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, SSE4_1); 44161cb0ef41Sopenharmony_ci if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp()); 44171cb0ef41Sopenharmony_ci pinsrd(dst.fp(), src2.gp(), imm_lane_idx); 44181cb0ef41Sopenharmony_ci } 44191cb0ef41Sopenharmony_ci} 44201cb0ef41Sopenharmony_ci 44211cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_i64x2_replace_lane(LiftoffRegister dst, 44221cb0ef41Sopenharmony_ci LiftoffRegister src1, 44231cb0ef41Sopenharmony_ci LiftoffRegister src2, 44241cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 44251cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 44261cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 44271cb0ef41Sopenharmony_ci vpinsrd(dst.fp(), src1.fp(), src2.low_gp(), imm_lane_idx * 2); 44281cb0ef41Sopenharmony_ci vpinsrd(dst.fp(), dst.fp(), src2.high_gp(), imm_lane_idx * 2 + 1); 44291cb0ef41Sopenharmony_ci } else { 44301cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, SSE4_1); 44311cb0ef41Sopenharmony_ci if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp()); 44321cb0ef41Sopenharmony_ci pinsrd(dst.fp(), src2.low_gp(), imm_lane_idx * 2); 44331cb0ef41Sopenharmony_ci pinsrd(dst.fp(), src2.high_gp(), imm_lane_idx * 2 + 1); 44341cb0ef41Sopenharmony_ci } 44351cb0ef41Sopenharmony_ci} 44361cb0ef41Sopenharmony_ci 44371cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f32x4_replace_lane(LiftoffRegister dst, 44381cb0ef41Sopenharmony_ci LiftoffRegister src1, 44391cb0ef41Sopenharmony_ci LiftoffRegister src2, 44401cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 44411cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(AVX)) { 44421cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, AVX); 44431cb0ef41Sopenharmony_ci vinsertps(dst.fp(), src1.fp(), src2.fp(), (imm_lane_idx << 4) & 0x30); 44441cb0ef41Sopenharmony_ci } else { 44451cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, SSE4_1); 44461cb0ef41Sopenharmony_ci if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp()); 44471cb0ef41Sopenharmony_ci insertps(dst.fp(), src2.fp(), (imm_lane_idx << 4) & 0x30); 44481cb0ef41Sopenharmony_ci } 44491cb0ef41Sopenharmony_ci} 44501cb0ef41Sopenharmony_ci 44511cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_f64x2_replace_lane(LiftoffRegister dst, 44521cb0ef41Sopenharmony_ci LiftoffRegister src1, 44531cb0ef41Sopenharmony_ci LiftoffRegister src2, 44541cb0ef41Sopenharmony_ci uint8_t imm_lane_idx) { 44551cb0ef41Sopenharmony_ci F64x2ReplaceLane(dst.fp(), src1.fp(), src2.fp(), imm_lane_idx); 44561cb0ef41Sopenharmony_ci} 44571cb0ef41Sopenharmony_ci 44581cb0ef41Sopenharmony_civoid LiftoffAssembler::StackCheck(Label* ool_code, Register limit_address) { 44591cb0ef41Sopenharmony_ci cmp(esp, Operand(limit_address, 0)); 44601cb0ef41Sopenharmony_ci j(below_equal, ool_code); 44611cb0ef41Sopenharmony_ci} 44621cb0ef41Sopenharmony_ci 44631cb0ef41Sopenharmony_civoid LiftoffAssembler::CallTrapCallbackForTesting() { 44641cb0ef41Sopenharmony_ci PrepareCallCFunction(0, GetUnusedRegister(kGpReg, {}).gp()); 44651cb0ef41Sopenharmony_ci CallCFunction(ExternalReference::wasm_call_trap_callback_for_testing(), 0); 44661cb0ef41Sopenharmony_ci} 44671cb0ef41Sopenharmony_ci 44681cb0ef41Sopenharmony_civoid LiftoffAssembler::AssertUnreachable(AbortReason reason) { 44691cb0ef41Sopenharmony_ci TurboAssembler::AssertUnreachable(reason); 44701cb0ef41Sopenharmony_ci} 44711cb0ef41Sopenharmony_ci 44721cb0ef41Sopenharmony_civoid LiftoffAssembler::PushRegisters(LiftoffRegList regs) { 44731cb0ef41Sopenharmony_ci LiftoffRegList gp_regs = regs & kGpCacheRegList; 44741cb0ef41Sopenharmony_ci while (!gp_regs.is_empty()) { 44751cb0ef41Sopenharmony_ci LiftoffRegister reg = gp_regs.GetFirstRegSet(); 44761cb0ef41Sopenharmony_ci push(reg.gp()); 44771cb0ef41Sopenharmony_ci gp_regs.clear(reg); 44781cb0ef41Sopenharmony_ci } 44791cb0ef41Sopenharmony_ci LiftoffRegList fp_regs = regs & kFpCacheRegList; 44801cb0ef41Sopenharmony_ci unsigned num_fp_regs = fp_regs.GetNumRegsSet(); 44811cb0ef41Sopenharmony_ci if (num_fp_regs) { 44821cb0ef41Sopenharmony_ci AllocateStackSpace(num_fp_regs * kSimd128Size); 44831cb0ef41Sopenharmony_ci unsigned offset = 0; 44841cb0ef41Sopenharmony_ci while (!fp_regs.is_empty()) { 44851cb0ef41Sopenharmony_ci LiftoffRegister reg = fp_regs.GetFirstRegSet(); 44861cb0ef41Sopenharmony_ci Movdqu(Operand(esp, offset), reg.fp()); 44871cb0ef41Sopenharmony_ci fp_regs.clear(reg); 44881cb0ef41Sopenharmony_ci offset += kSimd128Size; 44891cb0ef41Sopenharmony_ci } 44901cb0ef41Sopenharmony_ci DCHECK_EQ(offset, num_fp_regs * kSimd128Size); 44911cb0ef41Sopenharmony_ci } 44921cb0ef41Sopenharmony_ci} 44931cb0ef41Sopenharmony_ci 44941cb0ef41Sopenharmony_civoid LiftoffAssembler::PopRegisters(LiftoffRegList regs) { 44951cb0ef41Sopenharmony_ci LiftoffRegList fp_regs = regs & kFpCacheRegList; 44961cb0ef41Sopenharmony_ci unsigned fp_offset = 0; 44971cb0ef41Sopenharmony_ci while (!fp_regs.is_empty()) { 44981cb0ef41Sopenharmony_ci LiftoffRegister reg = fp_regs.GetFirstRegSet(); 44991cb0ef41Sopenharmony_ci Movdqu(reg.fp(), Operand(esp, fp_offset)); 45001cb0ef41Sopenharmony_ci fp_regs.clear(reg); 45011cb0ef41Sopenharmony_ci fp_offset += kSimd128Size; 45021cb0ef41Sopenharmony_ci } 45031cb0ef41Sopenharmony_ci if (fp_offset) add(esp, Immediate(fp_offset)); 45041cb0ef41Sopenharmony_ci LiftoffRegList gp_regs = regs & kGpCacheRegList; 45051cb0ef41Sopenharmony_ci while (!gp_regs.is_empty()) { 45061cb0ef41Sopenharmony_ci LiftoffRegister reg = gp_regs.GetLastRegSet(); 45071cb0ef41Sopenharmony_ci pop(reg.gp()); 45081cb0ef41Sopenharmony_ci gp_regs.clear(reg); 45091cb0ef41Sopenharmony_ci } 45101cb0ef41Sopenharmony_ci} 45111cb0ef41Sopenharmony_ci 45121cb0ef41Sopenharmony_civoid LiftoffAssembler::RecordSpillsInSafepoint( 45131cb0ef41Sopenharmony_ci SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills, 45141cb0ef41Sopenharmony_ci LiftoffRegList ref_spills, int spill_offset) { 45151cb0ef41Sopenharmony_ci int spill_space_size = 0; 45161cb0ef41Sopenharmony_ci while (!all_spills.is_empty()) { 45171cb0ef41Sopenharmony_ci LiftoffRegister reg = all_spills.GetFirstRegSet(); 45181cb0ef41Sopenharmony_ci if (ref_spills.has(reg)) { 45191cb0ef41Sopenharmony_ci safepoint.DefineTaggedStackSlot(spill_offset); 45201cb0ef41Sopenharmony_ci } 45211cb0ef41Sopenharmony_ci all_spills.clear(reg); 45221cb0ef41Sopenharmony_ci ++spill_offset; 45231cb0ef41Sopenharmony_ci spill_space_size += kSystemPointerSize; 45241cb0ef41Sopenharmony_ci } 45251cb0ef41Sopenharmony_ci // Record the number of additional spill slots. 45261cb0ef41Sopenharmony_ci RecordOolSpillSpaceSize(spill_space_size); 45271cb0ef41Sopenharmony_ci} 45281cb0ef41Sopenharmony_ci 45291cb0ef41Sopenharmony_civoid LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) { 45301cb0ef41Sopenharmony_ci DCHECK_LT(num_stack_slots, 45311cb0ef41Sopenharmony_ci (1 << 16) / kSystemPointerSize); // 16 bit immediate 45321cb0ef41Sopenharmony_ci ret(static_cast<int>(num_stack_slots * kSystemPointerSize)); 45331cb0ef41Sopenharmony_ci} 45341cb0ef41Sopenharmony_ci 45351cb0ef41Sopenharmony_civoid LiftoffAssembler::CallC(const ValueKindSig* sig, 45361cb0ef41Sopenharmony_ci const LiftoffRegister* args, 45371cb0ef41Sopenharmony_ci const LiftoffRegister* rets, 45381cb0ef41Sopenharmony_ci ValueKind out_argument_kind, int stack_bytes, 45391cb0ef41Sopenharmony_ci ExternalReference ext_ref) { 45401cb0ef41Sopenharmony_ci AllocateStackSpace(stack_bytes); 45411cb0ef41Sopenharmony_ci 45421cb0ef41Sopenharmony_ci int arg_bytes = 0; 45431cb0ef41Sopenharmony_ci for (ValueKind param_kind : sig->parameters()) { 45441cb0ef41Sopenharmony_ci liftoff::Store(this, esp, arg_bytes, *args++, param_kind); 45451cb0ef41Sopenharmony_ci arg_bytes += value_kind_size(param_kind); 45461cb0ef41Sopenharmony_ci } 45471cb0ef41Sopenharmony_ci DCHECK_LE(arg_bytes, stack_bytes); 45481cb0ef41Sopenharmony_ci 45491cb0ef41Sopenharmony_ci constexpr Register kScratch = eax; 45501cb0ef41Sopenharmony_ci constexpr Register kArgumentBuffer = ecx; 45511cb0ef41Sopenharmony_ci constexpr int kNumCCallArgs = 1; 45521cb0ef41Sopenharmony_ci mov(kArgumentBuffer, esp); 45531cb0ef41Sopenharmony_ci PrepareCallCFunction(kNumCCallArgs, kScratch); 45541cb0ef41Sopenharmony_ci 45551cb0ef41Sopenharmony_ci // Pass a pointer to the buffer with the arguments to the C function. ia32 45561cb0ef41Sopenharmony_ci // does not use registers here, so push to the stack. 45571cb0ef41Sopenharmony_ci mov(Operand(esp, 0), kArgumentBuffer); 45581cb0ef41Sopenharmony_ci 45591cb0ef41Sopenharmony_ci // Now call the C function. 45601cb0ef41Sopenharmony_ci CallCFunction(ext_ref, kNumCCallArgs); 45611cb0ef41Sopenharmony_ci 45621cb0ef41Sopenharmony_ci // Move return value to the right register. 45631cb0ef41Sopenharmony_ci const LiftoffRegister* next_result_reg = rets; 45641cb0ef41Sopenharmony_ci if (sig->return_count() > 0) { 45651cb0ef41Sopenharmony_ci DCHECK_EQ(1, sig->return_count()); 45661cb0ef41Sopenharmony_ci constexpr Register kReturnReg = eax; 45671cb0ef41Sopenharmony_ci if (kReturnReg != next_result_reg->gp()) { 45681cb0ef41Sopenharmony_ci Move(*next_result_reg, LiftoffRegister(kReturnReg), sig->GetReturn(0)); 45691cb0ef41Sopenharmony_ci } 45701cb0ef41Sopenharmony_ci ++next_result_reg; 45711cb0ef41Sopenharmony_ci } 45721cb0ef41Sopenharmony_ci 45731cb0ef41Sopenharmony_ci // Load potential output value from the buffer on the stack. 45741cb0ef41Sopenharmony_ci if (out_argument_kind != kVoid) { 45751cb0ef41Sopenharmony_ci liftoff::Load(this, *next_result_reg, esp, 0, out_argument_kind); 45761cb0ef41Sopenharmony_ci } 45771cb0ef41Sopenharmony_ci 45781cb0ef41Sopenharmony_ci add(esp, Immediate(stack_bytes)); 45791cb0ef41Sopenharmony_ci} 45801cb0ef41Sopenharmony_ci 45811cb0ef41Sopenharmony_civoid LiftoffAssembler::CallNativeWasmCode(Address addr) { 45821cb0ef41Sopenharmony_ci wasm_call(addr, RelocInfo::WASM_CALL); 45831cb0ef41Sopenharmony_ci} 45841cb0ef41Sopenharmony_ci 45851cb0ef41Sopenharmony_civoid LiftoffAssembler::TailCallNativeWasmCode(Address addr) { 45861cb0ef41Sopenharmony_ci jmp(addr, RelocInfo::WASM_CALL); 45871cb0ef41Sopenharmony_ci} 45881cb0ef41Sopenharmony_ci 45891cb0ef41Sopenharmony_civoid LiftoffAssembler::CallIndirect(const ValueKindSig* sig, 45901cb0ef41Sopenharmony_ci compiler::CallDescriptor* call_descriptor, 45911cb0ef41Sopenharmony_ci Register target) { 45921cb0ef41Sopenharmony_ci // Since we have more cache registers than parameter registers, the 45931cb0ef41Sopenharmony_ci // {LiftoffCompiler} should always be able to place {target} in a register. 45941cb0ef41Sopenharmony_ci DCHECK(target.is_valid()); 45951cb0ef41Sopenharmony_ci call(target); 45961cb0ef41Sopenharmony_ci} 45971cb0ef41Sopenharmony_ci 45981cb0ef41Sopenharmony_civoid LiftoffAssembler::TailCallIndirect(Register target) { 45991cb0ef41Sopenharmony_ci // Since we have more cache registers than parameter registers, the 46001cb0ef41Sopenharmony_ci // {LiftoffCompiler} should always be able to place {target} in a register. 46011cb0ef41Sopenharmony_ci DCHECK(target.is_valid()); 46021cb0ef41Sopenharmony_ci jmp(target); 46031cb0ef41Sopenharmony_ci} 46041cb0ef41Sopenharmony_ci 46051cb0ef41Sopenharmony_civoid LiftoffAssembler::CallRuntimeStub(WasmCode::RuntimeStubId sid) { 46061cb0ef41Sopenharmony_ci // A direct call to a wasm runtime stub defined in this module. 46071cb0ef41Sopenharmony_ci // Just encode the stub index. This will be patched at relocation. 46081cb0ef41Sopenharmony_ci wasm_call(static_cast<Address>(sid), RelocInfo::WASM_STUB_CALL); 46091cb0ef41Sopenharmony_ci} 46101cb0ef41Sopenharmony_ci 46111cb0ef41Sopenharmony_civoid LiftoffAssembler::AllocateStackSlot(Register addr, uint32_t size) { 46121cb0ef41Sopenharmony_ci AllocateStackSpace(size); 46131cb0ef41Sopenharmony_ci mov(addr, esp); 46141cb0ef41Sopenharmony_ci} 46151cb0ef41Sopenharmony_ci 46161cb0ef41Sopenharmony_civoid LiftoffAssembler::DeallocateStackSlot(uint32_t size) { 46171cb0ef41Sopenharmony_ci add(esp, Immediate(size)); 46181cb0ef41Sopenharmony_ci} 46191cb0ef41Sopenharmony_ci 46201cb0ef41Sopenharmony_civoid LiftoffAssembler::MaybeOSR() {} 46211cb0ef41Sopenharmony_ci 46221cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_set_if_nan(Register dst, DoubleRegister src, 46231cb0ef41Sopenharmony_ci ValueKind kind) { 46241cb0ef41Sopenharmony_ci if (kind == kF32) { 46251cb0ef41Sopenharmony_ci ucomiss(src, src); 46261cb0ef41Sopenharmony_ci } else { 46271cb0ef41Sopenharmony_ci DCHECK_EQ(kind, kF64); 46281cb0ef41Sopenharmony_ci ucomisd(src, src); 46291cb0ef41Sopenharmony_ci } 46301cb0ef41Sopenharmony_ci Label ret; 46311cb0ef41Sopenharmony_ci j(parity_odd, &ret); 46321cb0ef41Sopenharmony_ci mov(Operand(dst, 0), Immediate(1)); 46331cb0ef41Sopenharmony_ci bind(&ret); 46341cb0ef41Sopenharmony_ci} 46351cb0ef41Sopenharmony_ci 46361cb0ef41Sopenharmony_civoid LiftoffAssembler::emit_s128_set_if_nan(Register dst, LiftoffRegister src, 46371cb0ef41Sopenharmony_ci Register tmp_gp, 46381cb0ef41Sopenharmony_ci LiftoffRegister tmp_s128, 46391cb0ef41Sopenharmony_ci ValueKind lane_kind) { 46401cb0ef41Sopenharmony_ci if (lane_kind == kF32) { 46411cb0ef41Sopenharmony_ci movaps(tmp_s128.fp(), src.fp()); 46421cb0ef41Sopenharmony_ci cmpunordps(tmp_s128.fp(), tmp_s128.fp()); 46431cb0ef41Sopenharmony_ci } else { 46441cb0ef41Sopenharmony_ci DCHECK_EQ(lane_kind, kF64); 46451cb0ef41Sopenharmony_ci movapd(tmp_s128.fp(), src.fp()); 46461cb0ef41Sopenharmony_ci cmpunordpd(tmp_s128.fp(), tmp_s128.fp()); 46471cb0ef41Sopenharmony_ci } 46481cb0ef41Sopenharmony_ci pmovmskb(tmp_gp, tmp_s128.fp()); 46491cb0ef41Sopenharmony_ci or_(Operand(dst, 0), tmp_gp); 46501cb0ef41Sopenharmony_ci} 46511cb0ef41Sopenharmony_ci 46521cb0ef41Sopenharmony_civoid LiftoffStackSlots::Construct(int param_slots) { 46531cb0ef41Sopenharmony_ci DCHECK_LT(0, slots_.size()); 46541cb0ef41Sopenharmony_ci SortInPushOrder(); 46551cb0ef41Sopenharmony_ci int last_stack_slot = param_slots; 46561cb0ef41Sopenharmony_ci for (auto& slot : slots_) { 46571cb0ef41Sopenharmony_ci const int stack_slot = slot.dst_slot_; 46581cb0ef41Sopenharmony_ci int stack_decrement = (last_stack_slot - stack_slot) * kSystemPointerSize; 46591cb0ef41Sopenharmony_ci DCHECK_LT(0, stack_decrement); 46601cb0ef41Sopenharmony_ci last_stack_slot = stack_slot; 46611cb0ef41Sopenharmony_ci const LiftoffAssembler::VarState& src = slot.src_; 46621cb0ef41Sopenharmony_ci switch (src.loc()) { 46631cb0ef41Sopenharmony_ci case LiftoffAssembler::VarState::kStack: 46641cb0ef41Sopenharmony_ci // The combination of AllocateStackSpace and 2 movdqu is usually smaller 46651cb0ef41Sopenharmony_ci // in code size than doing 4 pushes. 46661cb0ef41Sopenharmony_ci if (src.kind() == kS128) { 46671cb0ef41Sopenharmony_ci asm_->AllocateStackSpace(stack_decrement); 46681cb0ef41Sopenharmony_ci asm_->movdqu(liftoff::kScratchDoubleReg, 46691cb0ef41Sopenharmony_ci liftoff::GetStackSlot(slot.src_offset_)); 46701cb0ef41Sopenharmony_ci asm_->movdqu(Operand(esp, 0), liftoff::kScratchDoubleReg); 46711cb0ef41Sopenharmony_ci break; 46721cb0ef41Sopenharmony_ci } 46731cb0ef41Sopenharmony_ci if (src.kind() == kF64) { 46741cb0ef41Sopenharmony_ci asm_->AllocateStackSpace(stack_decrement - kDoubleSize); 46751cb0ef41Sopenharmony_ci DCHECK_EQ(kLowWord, slot.half_); 46761cb0ef41Sopenharmony_ci asm_->push(liftoff::GetHalfStackSlot(slot.src_offset_, kHighWord)); 46771cb0ef41Sopenharmony_ci stack_decrement = kSystemPointerSize; 46781cb0ef41Sopenharmony_ci } 46791cb0ef41Sopenharmony_ci asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); 46801cb0ef41Sopenharmony_ci asm_->push(liftoff::GetHalfStackSlot(slot.src_offset_, slot.half_)); 46811cb0ef41Sopenharmony_ci break; 46821cb0ef41Sopenharmony_ci case LiftoffAssembler::VarState::kRegister: 46831cb0ef41Sopenharmony_ci if (src.kind() == kI64) { 46841cb0ef41Sopenharmony_ci liftoff::push( 46851cb0ef41Sopenharmony_ci asm_, slot.half_ == kLowWord ? src.reg().low() : src.reg().high(), 46861cb0ef41Sopenharmony_ci kI32, stack_decrement - kSystemPointerSize); 46871cb0ef41Sopenharmony_ci } else { 46881cb0ef41Sopenharmony_ci int pushed_bytes = SlotSizeInBytes(slot); 46891cb0ef41Sopenharmony_ci liftoff::push(asm_, src.reg(), src.kind(), 46901cb0ef41Sopenharmony_ci stack_decrement - pushed_bytes); 46911cb0ef41Sopenharmony_ci } 46921cb0ef41Sopenharmony_ci break; 46931cb0ef41Sopenharmony_ci case LiftoffAssembler::VarState::kIntConst: 46941cb0ef41Sopenharmony_ci asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); 46951cb0ef41Sopenharmony_ci // The high word is the sign extension of the low word. 46961cb0ef41Sopenharmony_ci asm_->push(Immediate(slot.half_ == kLowWord ? src.i32_const() 46971cb0ef41Sopenharmony_ci : src.i32_const() >> 31)); 46981cb0ef41Sopenharmony_ci break; 46991cb0ef41Sopenharmony_ci } 47001cb0ef41Sopenharmony_ci } 47011cb0ef41Sopenharmony_ci} 47021cb0ef41Sopenharmony_ci 47031cb0ef41Sopenharmony_ci#undef RETURN_FALSE_IF_MISSING_CPU_FEATURE 47041cb0ef41Sopenharmony_ci 47051cb0ef41Sopenharmony_ci} // namespace wasm 47061cb0ef41Sopenharmony_ci} // namespace internal 47071cb0ef41Sopenharmony_ci} // namespace v8 47081cb0ef41Sopenharmony_ci 47091cb0ef41Sopenharmony_ci#endif // V8_WASM_BASELINE_IA32_LIFTOFF_ASSEMBLER_IA32_H_ 4710