aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h')
-rw-r--r--deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h219
1 files changed, 145 insertions, 74 deletions
diff --git a/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h b/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
index 3a0ace0d62..067c79be32 100644
--- a/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
+++ b/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32.h
@@ -34,8 +34,10 @@ inline Operand GetStackSlot(uint32_t index) {
return Operand(ebp, -kFirstStackSlotOffset - offset);
}
-inline Operand GetHalfStackSlot(uint32_t half_index) {
- int32_t offset = half_index * (LiftoffAssembler::kStackSlotSize / 2);
+inline MemOperand GetHalfStackSlot(uint32_t index, RegPairHalf half) {
+ int32_t half_offset =
+ half == kLowWord ? 0 : LiftoffAssembler::kStackSlotSize / 2;
+ int32_t offset = index * LiftoffAssembler::kStackSlotSize - half_offset;
return Operand(ebp, -kFirstStackSlotOffset - offset);
}
@@ -43,10 +45,7 @@ inline Operand GetHalfStackSlot(uint32_t half_index) {
inline Operand GetInstanceOperand() { return Operand(ebp, -8); }
static constexpr LiftoffRegList kByteRegs =
- LiftoffRegList::FromBits<Register::ListOf<eax, ecx, edx, ebx>()>();
-static_assert(kByteRegs.GetNumRegsSet() == 4, "should have four byte regs");
-static_assert((kByteRegs & kGpCacheRegList) == kByteRegs,
- "kByteRegs only contains gp cache registers");
+ LiftoffRegList::FromBits<Register::ListOf<eax, ecx, edx>()>();
inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base,
int32_t offset, ValueType type) {
@@ -126,6 +125,28 @@ inline void SignExtendI32ToI64(Assembler* assm, LiftoffRegister reg) {
assm->sar(reg.high_gp(), 31);
}
+// Get a temporary byte register, using {candidate} if possible.
+// Might spill, but always keeps status flags intact.
+inline Register GetTmpByteRegister(LiftoffAssembler* assm, Register candidate) {
+ if (candidate.is_byte_register()) return candidate;
+ // {GetUnusedRegister()} may insert move instructions to spill registers to
+ // the stack. This is OK because {mov} does not change the status flags.
+ return assm->GetUnusedRegister(liftoff::kByteRegs).gp();
+}
+
+inline void MoveStackValue(LiftoffAssembler* assm, const Operand& src,
+ const Operand& dst) {
+ if (assm->cache_state()->has_unused_register(kGpReg)) {
+ Register tmp = assm->cache_state()->unused_register(kGpReg).gp();
+ assm->mov(tmp, src);
+ assm->mov(dst, tmp);
+ } else {
+ // No free register, move via the stack.
+ assm->push(src);
+ assm->pop(dst);
+ }
+}
+
constexpr DoubleRegister kScratchDoubleReg = xmm7;
constexpr int kSubSpSize = 6; // 6 bytes for "sub esp, <imm32>"
@@ -146,8 +167,9 @@ void LiftoffAssembler::PatchPrepareStackFrame(int offset,
// We can't run out of space, just pass anything big enough to not cause the
// assembler to try to grow the buffer.
constexpr int kAvailableSpace = 64;
- Assembler patching_assembler(AssemblerOptions{}, buffer_ + offset,
- kAvailableSpace);
+ Assembler patching_assembler(
+ AssemblerOptions{},
+ ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace));
#if V8_OS_WIN
constexpr int kPageSize = 4 * 1024;
if (bytes > kPageSize) {
@@ -216,6 +238,11 @@ void LiftoffAssembler::LoadFromInstance(Register dst, uint32_t offset,
mov(dst, Operand(dst, offset));
}
+void LiftoffAssembler::LoadTaggedPointerFromInstance(Register dst,
+ uint32_t offset) {
+ LoadFromInstance(dst, offset, kTaggedSize);
+}
+
void LiftoffAssembler::SpillInstance(Register instance) {
mov(liftoff::GetInstanceOperand(), instance);
}
@@ -224,6 +251,15 @@ void LiftoffAssembler::FillInstanceInto(Register dst) {
mov(dst, liftoff::GetInstanceOperand());
}
+void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr,
+ Register offset_reg,
+ uint32_t offset_imm,
+ LiftoffRegList pinned) {
+ STATIC_ASSERT(kTaggedSize == kInt32Size);
+ Load(LiftoffRegister(dst), src_addr, offset_reg, offset_imm,
+ LoadType::kI32Load, pinned);
+}
+
void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm,
LoadType type, LiftoffRegList pinned,
@@ -324,7 +360,13 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
if (src.gp().is_byte_register()) {
mov_b(dst_op, src.gp());
} else {
- Register byte_src = GetUnusedRegister(liftoff::kByteRegs, pinned).gp();
+ // We know that {src} is not a byte register, so the only pinned byte
+ // registers (beside the outer {pinned}) are {dst_addr} and potentially
+ // {offset_reg}.
+ LiftoffRegList pinned_byte = pinned | LiftoffRegList::ForRegs(dst_addr);
+ if (offset_reg != no_reg) pinned_byte.set(offset_reg);
+ Register byte_src =
+ GetUnusedRegister(liftoff::kByteRegs, pinned_byte).gp();
mov(byte_src, src.gp());
mov_b(dst_op, byte_src);
}
@@ -367,19 +409,22 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
- liftoff::Load(this, dst, ebp, kPointerSize * (caller_slot_idx + 1), type);
+ liftoff::Load(this, dst, ebp, kSystemPointerSize * (caller_slot_idx + 1),
+ type);
}
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
ValueType type) {
- DCHECK_NE(dst_index, src_index);
- if (cache_state_.has_unused_register(kGpReg)) {
- LiftoffRegister reg = GetUnusedRegister(kGpReg);
- Fill(reg, src_index, type);
- Spill(dst_index, reg, type);
+ if (needs_reg_pair(type)) {
+ liftoff::MoveStackValue(this,
+ liftoff::GetHalfStackSlot(src_index, kLowWord),
+ liftoff::GetHalfStackSlot(dst_index, kLowWord));
+ liftoff::MoveStackValue(this,
+ liftoff::GetHalfStackSlot(src_index, kHighWord),
+ liftoff::GetHalfStackSlot(dst_index, kHighWord));
} else {
- push(liftoff::GetStackSlot(src_index));
- pop(liftoff::GetStackSlot(dst_index));
+ liftoff::MoveStackValue(this, liftoff::GetStackSlot(src_index),
+ liftoff::GetStackSlot(dst_index));
}
}
@@ -409,8 +454,8 @@ void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
mov(dst, reg.gp());
break;
case kWasmI64:
- mov(dst, reg.low_gp());
- mov(liftoff::GetHalfStackSlot(2 * index - 1), reg.high_gp());
+ mov(liftoff::GetHalfStackSlot(index, kLowWord), reg.low_gp());
+ mov(liftoff::GetHalfStackSlot(index, kHighWord), reg.high_gp());
break;
case kWasmF32:
movss(dst, reg.fp());
@@ -433,8 +478,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
case kWasmI64: {
int32_t low_word = value.to_i64();
int32_t high_word = value.to_i64() >> 32;
- mov(dst, Immediate(low_word));
- mov(liftoff::GetHalfStackSlot(2 * index - 1), Immediate(high_word));
+ mov(liftoff::GetHalfStackSlot(index, kLowWord), Immediate(low_word));
+ mov(liftoff::GetHalfStackSlot(index, kHighWord), Immediate(high_word));
break;
}
default:
@@ -451,8 +496,8 @@ void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
mov(reg.gp(), src);
break;
case kWasmI64:
- mov(reg.low_gp(), src);
- mov(reg.high_gp(), liftoff::GetHalfStackSlot(2 * index - 1));
+ mov(reg.low_gp(), liftoff::GetHalfStackSlot(index, kLowWord));
+ mov(reg.high_gp(), liftoff::GetHalfStackSlot(index, kHighWord));
break;
case kWasmF32:
movss(reg.fp(), src);
@@ -465,8 +510,9 @@ void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
}
}
-void LiftoffAssembler::FillI64Half(Register reg, uint32_t half_index) {
- mov(reg, liftoff::GetHalfStackSlot(half_index));
+void LiftoffAssembler::FillI64Half(Register reg, uint32_t index,
+ RegPairHalf half) {
+ mov(reg, liftoff::GetHalfStackSlot(index, half));
}
void LiftoffAssembler::emit_i32_add(Register dst, Register lhs, Register rhs) {
@@ -478,12 +524,17 @@ void LiftoffAssembler::emit_i32_add(Register dst, Register lhs, Register rhs) {
}
void LiftoffAssembler::emit_i32_sub(Register dst, Register lhs, Register rhs) {
- if (dst == rhs) {
- neg(dst);
- add(dst, lhs);
- } else {
+ if (dst != rhs) {
+ // Default path.
if (dst != lhs) mov(dst, lhs);
sub(dst, rhs);
+ } else if (lhs == rhs) {
+ // Degenerate case.
+ xor_(dst, dst);
+ } else {
+ // Emit {dst = lhs + -rhs} if dst == rhs.
+ neg(dst);
+ add(dst, lhs);
}
}
@@ -768,15 +819,16 @@ void LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs,
Register lhs_hi = ecx;
Register lhs_lo = dst_lo;
Register rhs_hi = dst_hi;
- Register rhs_lo = ebx;
+ Register rhs_lo = esi;
// Spill all these registers if they are still holding other values.
liftoff::SpillRegisters(this, dst_hi, dst_lo, lhs_hi, rhs_lo);
// Move lhs and rhs into the respective registers.
- ParallelRegisterMove(
- {{LiftoffRegister::ForPair(lhs_lo, lhs_hi), lhs, kWasmI64},
- {LiftoffRegister::ForPair(rhs_lo, rhs_hi), rhs, kWasmI64}});
+ ParallelRegisterMoveTuple reg_moves[]{
+ {LiftoffRegister::ForPair(lhs_lo, lhs_hi), lhs, kWasmI64},
+ {LiftoffRegister::ForPair(rhs_lo, rhs_hi), rhs, kWasmI64}};
+ ParallelRegisterMove(ArrayVector(reg_moves));
// First mul: lhs_hi' = lhs_hi * rhs_lo.
imul(lhs_hi, rhs_lo);
@@ -784,7 +836,7 @@ void LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs,
imul(rhs_hi, lhs_lo);
// Add them: lhs_hi'' = lhs_hi' + rhs_hi' = lhs_hi * rhs_lo + rhs_hi * lhs_lo.
add(lhs_hi, rhs_hi);
- // Third mul: edx:eax (dst_hi:dst_lo) = eax * ebx (lhs_lo * rhs_lo).
+ // Third mul: edx:eax (dst_hi:dst_lo) = eax * esi (lhs_lo * rhs_lo).
mul(rhs_lo);
// Add lhs_hi'' to dst_hi.
add(dst_hi, lhs_hi);
@@ -839,27 +891,32 @@ inline void Emit64BitShiftOperation(
LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister src,
Register amount, void (TurboAssembler::*emit_shift)(Register, Register),
LiftoffRegList pinned) {
+ // Temporary registers cannot overlap with {dst}.
pinned.set(dst);
- pinned.set(src);
- pinned.set(amount);
+
+ constexpr size_t kMaxRegMoves = 3;
+ base::SmallVector<LiftoffAssembler::ParallelRegisterMoveTuple, kMaxRegMoves>
+ reg_moves;
+
// If {dst} contains {ecx}, replace it by an unused register, which is then
// moved to {ecx} in the end.
Register ecx_replace = no_reg;
if (PairContains(dst, ecx)) {
- ecx_replace = pinned.set(assm->GetUnusedRegister(kGpReg, pinned)).gp();
+ ecx_replace = assm->GetUnusedRegister(kGpReg, pinned).gp();
dst = ReplaceInPair(dst, ecx, ecx_replace);
// If {amount} needs to be moved to {ecx}, but {ecx} is in use (and not part
// of {dst}, hence overwritten anyway), move {ecx} to a tmp register and
// restore it at the end.
} else if (amount != ecx &&
- assm->cache_state()->is_used(LiftoffRegister(ecx))) {
+ (assm->cache_state()->is_used(LiftoffRegister(ecx)) ||
+ pinned.has(LiftoffRegister(ecx)))) {
ecx_replace = assm->GetUnusedRegister(kGpReg, pinned).gp();
- assm->mov(ecx_replace, ecx);
+ reg_moves.emplace_back(ecx_replace, ecx, kWasmI32);
}
- assm->ParallelRegisterMove(
- {{dst, src, kWasmI64},
- {LiftoffRegister{ecx}, LiftoffRegister{amount}, kWasmI32}});
+ reg_moves.emplace_back(dst, src, kWasmI64);
+ reg_moves.emplace_back(ecx, amount, kWasmI32);
+ assm->ParallelRegisterMove(VectorOf(reg_moves));
// Do the actual shift.
(assm->*emit_shift)(dst.high_gp(), dst.low_gp());
@@ -1063,25 +1120,41 @@ void LiftoffAssembler::emit_f32_neg(DoubleRegister dst, DoubleRegister src) {
}
}
-void LiftoffAssembler::emit_f32_ceil(DoubleRegister dst, DoubleRegister src) {
- REQUIRE_CPU_FEATURE(SSE4_1);
- roundss(dst, src, kRoundUp);
+bool LiftoffAssembler::emit_f32_ceil(DoubleRegister dst, DoubleRegister src) {
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope feature(this, SSE4_1);
+ roundss(dst, src, kRoundUp);
+ return true;
+ }
+ return false;
}
-void LiftoffAssembler::emit_f32_floor(DoubleRegister dst, DoubleRegister src) {
- REQUIRE_CPU_FEATURE(SSE4_1);
- roundss(dst, src, kRoundDown);
+bool LiftoffAssembler::emit_f32_floor(DoubleRegister dst, DoubleRegister src) {
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope feature(this, SSE4_1);
+ roundss(dst, src, kRoundDown);
+ return true;
+ }
+ return false;
}
-void LiftoffAssembler::emit_f32_trunc(DoubleRegister dst, DoubleRegister src) {
- REQUIRE_CPU_FEATURE(SSE4_1);
- roundss(dst, src, kRoundToZero);
+bool LiftoffAssembler::emit_f32_trunc(DoubleRegister dst, DoubleRegister src) {
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope feature(this, SSE4_1);
+ roundss(dst, src, kRoundToZero);
+ return true;
+ }
+ return false;
}
-void LiftoffAssembler::emit_f32_nearest_int(DoubleRegister dst,
+bool LiftoffAssembler::emit_f32_nearest_int(DoubleRegister dst,
DoubleRegister src) {
- REQUIRE_CPU_FEATURE(SSE4_1);
- roundss(dst, src, kRoundToNearest);
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatureScope feature(this, SSE4_1);
+ roundss(dst, src, kRoundToNearest);
+ return true;
+ }
+ return false;
}
void LiftoffAssembler::emit_f32_sqrt(DoubleRegister dst, DoubleRegister src) {
@@ -1239,7 +1312,8 @@ inline void ConvertFloatToIntAndBack(LiftoffAssembler* assm, Register dst,
assm->Cvtsi2sd(converted_back, dst);
} else { // f64 -> u32
assm->Cvttsd2ui(dst, src, liftoff::kScratchDoubleReg);
- assm->Cvtui2sd(converted_back, dst);
+ assm->Cvtui2sd(converted_back, dst,
+ assm->GetUnusedRegister(kGpReg, pinned).gp());
}
} else { // f32
if (std::is_signed<dst_type>::value) { // f32 -> i32
@@ -1346,9 +1420,12 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
case kExprF64SConvertI32:
Cvtsi2sd(dst.fp(), src.gp());
return true;
- case kExprF64UConvertI32:
- Cvtui2sd(dst.fp(), src.gp());
+ case kExprF64UConvertI32: {
+ LiftoffRegList pinned = LiftoffRegList::ForRegs(dst, src);
+ Register scratch = GetUnusedRegister(kGpReg, pinned).gp();
+ Cvtui2sd(dst.fp(), src.gp(), scratch);
return true;
+ }
case kExprF64ConvertF32:
cvtss2sd(dst.fp(), src.fp());
return true;
@@ -1366,7 +1443,9 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
}
void LiftoffAssembler::emit_i32_signextend_i8(Register dst, Register src) {
- movsx_b(dst, src);
+ Register byte_reg = liftoff::GetTmpByteRegister(this, src);
+ if (byte_reg != src) mov(byte_reg, src);
+ movsx_b(dst, byte_reg);
}
void LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) {
@@ -1375,7 +1454,9 @@ void LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) {
void LiftoffAssembler::emit_i64_signextend_i8(LiftoffRegister dst,
LiftoffRegister src) {
- movsx_b(dst.low_gp(), src.low_gp());
+ Register byte_reg = liftoff::GetTmpByteRegister(this, src.low_gp());
+ if (byte_reg != src.low_gp()) mov(byte_reg, src.low_gp());
+ movsx_b(dst.low_gp(), byte_reg);
liftoff::SignExtendI32ToI64(this, dst);
}
@@ -1416,16 +1497,6 @@ void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label,
namespace liftoff {
-// Get a temporary byte register, using {candidate} if possible.
-// Might spill, but always keeps status flags intact.
-inline Register GetTmpByteRegister(LiftoffAssembler* assm, Register candidate) {
- if (candidate.is_byte_register()) return candidate;
- LiftoffRegList pinned = LiftoffRegList::ForRegs(candidate);
- // {GetUnusedRegister()} may insert move instructions to spill registers to
- // the stack. This is OK because {mov} does not change the status flags.
- return assm->GetUnusedRegister(liftoff::kByteRegs, pinned).gp();
-}
-
// Setcc into dst register, given a scratch byte register (might be the same as
// dst). Never spills.
inline void setcc_32_no_spill(LiftoffAssembler* assm, Condition cond,
@@ -1606,8 +1677,9 @@ void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {
}
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {
- DCHECK_LT(num_stack_slots, (1 << 16) / kPointerSize); // 16 bit immediate
- ret(static_cast<int>(num_stack_slots * kPointerSize));
+ DCHECK_LT(num_stack_slots,
+ (1 << 16) / kSystemPointerSize); // 16 bit immediate
+ ret(static_cast<int>(num_stack_slots * kSystemPointerSize));
}
void LiftoffAssembler::CallC(wasm::FunctionSig* sig,
@@ -1695,10 +1767,9 @@ void LiftoffStackSlots::Construct() {
case LiftoffAssembler::VarState::kStack:
if (src.type() == kWasmF64) {
DCHECK_EQ(kLowWord, slot.half_);
- asm_->push(liftoff::GetHalfStackSlot(2 * slot.src_index_ - 1));
+ asm_->push(liftoff::GetHalfStackSlot(slot.src_index_, kHighWord));
}
- asm_->push(liftoff::GetHalfStackSlot(2 * slot.src_index_ -
- (slot.half_ == kLowWord ? 0 : 1)));
+ asm_->push(liftoff::GetHalfStackSlot(slot.src_index_, slot.half_));
break;
case LiftoffAssembler::VarState::kRegister:
if (src.type() == kWasmI64) {