[Liftoff] Implement i64 shifts
This adds support for i64.shl, i64.shr_s, and i64.shr_u. R=titzer@chromium.org Bug: v8:6600 Change-Id: Ibc1982064ff3c9f3a494b5fa329841a0d3bc7bce Reviewed-on: https://chromium-review.googlesource.com/964844 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#52022}
This commit is contained in:
parent
dfc2805ccf
commit
d9fd12cfb3
@ -179,7 +179,7 @@ class TurboAssembler : public Assembler {
|
||||
void ShlPair(Register high, Register low, uint8_t imm8);
|
||||
void ShlPair_cl(Register high, Register low);
|
||||
void ShrPair(Register high, Register low, uint8_t imm8);
|
||||
void ShrPair_cl(Register high, Register src);
|
||||
void ShrPair_cl(Register high, Register low);
|
||||
void SarPair(Register high, Register low, uint8_t imm8);
|
||||
void SarPair_cl(Register high, Register low);
|
||||
|
||||
|
@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
|
||||
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
|
||||
BAILOUT("fp unop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \
|
||||
LiftoffRegList pinned) { \
|
||||
BAILOUT("shiftop"); \
|
||||
#define UNIMPLEMENTED_I32_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i32 shiftop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_I64_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(LiftoffRegister dst, LiftoffRegister src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i64 shiftop"); \
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_GP_BINOP(i32_add)
|
||||
@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_and)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_or)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_xor)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shl)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_sar)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shr)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_clz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_ctz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_popcnt)
|
||||
@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
|
||||
#undef UNIMPLEMENTED_GP_UNOP
|
||||
#undef UNIMPLEMENTED_FP_BINOP
|
||||
#undef UNIMPLEMENTED_FP_UNOP
|
||||
#undef UNIMPLEMENTED_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I32_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I64_SHIFTOP
|
||||
|
||||
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
|
||||
LiftoffRegister dst,
|
||||
|
@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
|
||||
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
|
||||
BAILOUT("fp unop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \
|
||||
LiftoffRegList pinned) { \
|
||||
BAILOUT("shiftop"); \
|
||||
#define UNIMPLEMENTED_I32_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i32 shiftop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_I64_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(LiftoffRegister dst, LiftoffRegister src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i64 shiftop"); \
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_GP_BINOP(i32_add)
|
||||
@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_and)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_or)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_xor)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shl)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_sar)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shr)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_clz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_ctz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_popcnt)
|
||||
@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
|
||||
#undef UNIMPLEMENTED_GP_UNOP
|
||||
#undef UNIMPLEMENTED_FP_BINOP
|
||||
#undef UNIMPLEMENTED_FP_UNOP
|
||||
#undef UNIMPLEMENTED_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I32_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I64_SHIFTOP
|
||||
|
||||
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
|
||||
LiftoffRegister dst,
|
||||
|
@ -318,10 +318,9 @@ void LiftoffAssembler::MoveToReturnRegister(LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
// TODO(wasm): Extract the destination register from the CallDescriptor.
|
||||
// TODO(wasm): Add multi-return support.
|
||||
LiftoffRegister dst =
|
||||
reg.is_pair()
|
||||
? LiftoffRegister::ForPair(LiftoffRegister(eax), LiftoffRegister(edx))
|
||||
: reg.is_gp() ? LiftoffRegister(eax) : LiftoffRegister(xmm1);
|
||||
LiftoffRegister dst = reg.is_pair() ? LiftoffRegister::ForPair(eax, edx)
|
||||
: reg.is_gp() ? LiftoffRegister(eax)
|
||||
: LiftoffRegister(xmm1);
|
||||
if (reg != dst) Move(dst, reg, type);
|
||||
}
|
||||
|
||||
@ -451,37 +450,37 @@ COMMUTATIVE_I32_BINOP(xor, xor_)
|
||||
|
||||
namespace liftoff {
|
||||
inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
|
||||
Register lhs, Register rhs,
|
||||
Register src, Register amount,
|
||||
void (Assembler::*emit_shift)(Register),
|
||||
LiftoffRegList pinned) {
|
||||
pinned.set(dst);
|
||||
pinned.set(lhs);
|
||||
pinned.set(rhs);
|
||||
pinned.set(src);
|
||||
pinned.set(amount);
|
||||
// If dst is ecx, compute into a tmp register first, then move to ecx.
|
||||
if (dst == ecx) {
|
||||
Register tmp = assm->GetUnusedRegister(kGpReg, pinned).gp();
|
||||
assm->mov(tmp, lhs);
|
||||
if (rhs != ecx) assm->mov(ecx, rhs);
|
||||
assm->mov(tmp, src);
|
||||
if (amount != ecx) assm->mov(ecx, amount);
|
||||
(assm->*emit_shift)(tmp);
|
||||
assm->mov(ecx, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move rhs into ecx. If ecx is in use, move its content to a tmp register
|
||||
// first. If lhs is ecx, lhs is now the tmp register.
|
||||
// Move amount into ecx. If ecx is in use, move its content to a tmp register
|
||||
// first. If src is ecx, src is now the tmp register.
|
||||
Register tmp_reg = no_reg;
|
||||
if (rhs != ecx) {
|
||||
if (amount != ecx) {
|
||||
if (assm->cache_state()->is_used(LiftoffRegister(ecx)) ||
|
||||
pinned.has(LiftoffRegister(ecx))) {
|
||||
tmp_reg = assm->GetUnusedRegister(kGpReg, pinned).gp();
|
||||
assm->mov(tmp_reg, ecx);
|
||||
if (lhs == ecx) lhs = tmp_reg;
|
||||
if (src == ecx) src = tmp_reg;
|
||||
}
|
||||
assm->mov(ecx, rhs);
|
||||
assm->mov(ecx, amount);
|
||||
}
|
||||
|
||||
// Do the actual shift.
|
||||
if (dst != lhs) assm->mov(dst, lhs);
|
||||
if (dst != src) assm->mov(dst, src);
|
||||
(assm->*emit_shift)(dst);
|
||||
|
||||
// Restore ecx if needed.
|
||||
@ -489,19 +488,22 @@ inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
|
||||
}
|
||||
} // namespace liftoff
|
||||
|
||||
void LiftoffAssembler::emit_i32_shl(Register dst, Register lhs, Register rhs,
|
||||
void LiftoffAssembler::emit_i32_shl(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation(this, dst, lhs, rhs, &Assembler::shl_cl, pinned);
|
||||
liftoff::EmitShiftOperation(this, dst, src, amount, &Assembler::shl_cl,
|
||||
pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i32_sar(Register dst, Register lhs, Register rhs,
|
||||
void LiftoffAssembler::emit_i32_sar(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation(this, dst, lhs, rhs, &Assembler::sar_cl, pinned);
|
||||
liftoff::EmitShiftOperation(this, dst, src, amount, &Assembler::sar_cl,
|
||||
pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i32_shr(Register dst, Register lhs, Register rhs,
|
||||
void LiftoffAssembler::emit_i32_shr(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation(this, dst, lhs, rhs, &Assembler::shr_cl, pinned);
|
||||
liftoff::EmitShiftOperation(this, dst, src, amount, &Assembler::shr_cl,
|
||||
pinned);
|
||||
}
|
||||
|
||||
bool LiftoffAssembler::emit_i32_clz(Register dst, Register src) {
|
||||
@ -545,6 +547,77 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace liftoff {
|
||||
inline bool PairContains(LiftoffRegister pair, Register reg) {
|
||||
return pair.low_gp() == reg || pair.high_gp() == reg;
|
||||
}
|
||||
|
||||
inline LiftoffRegister ReplaceInPair(LiftoffRegister pair, Register old_reg,
|
||||
Register new_reg) {
|
||||
if (pair.low_gp() == old_reg) {
|
||||
return LiftoffRegister::ForPair(new_reg, pair.high_gp());
|
||||
}
|
||||
if (pair.high_gp() == old_reg) {
|
||||
return LiftoffRegister::ForPair(pair.low_gp(), new_reg);
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
inline void Emit64BitShiftOperation(
|
||||
LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, void (TurboAssembler::*emit_shift)(Register, Register),
|
||||
LiftoffRegList pinned) {
|
||||
pinned.set(dst);
|
||||
pinned.set(src);
|
||||
pinned.set(amount);
|
||||
// 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();
|
||||
dst = ReplaceInPair(dst, ecx, ecx_replace);
|
||||
}
|
||||
|
||||
// Move src to dst.
|
||||
if (dst != src) assm->Move(dst, src, kWasmI64);
|
||||
|
||||
// Move amount into ecx. If ecx is in use and not part of dst, move its
|
||||
// content to a tmp register first.
|
||||
if (amount != ecx) {
|
||||
if (assm->cache_state()->is_used(LiftoffRegister(ecx)) &&
|
||||
ecx_replace == no_reg) {
|
||||
ecx_replace = assm->GetUnusedRegister(kGpReg, pinned).gp();
|
||||
assm->mov(ecx_replace, ecx);
|
||||
}
|
||||
assm->mov(ecx, amount);
|
||||
}
|
||||
|
||||
// Do the actual shift.
|
||||
(assm->*emit_shift)(dst.high_gp(), dst.low_gp());
|
||||
|
||||
// Restore ecx if needed.
|
||||
if (ecx_replace != no_reg) assm->mov(ecx, ecx_replace);
|
||||
}
|
||||
} // namespace liftoff
|
||||
|
||||
void LiftoffAssembler::emit_i64_shl(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned) {
|
||||
liftoff::Emit64BitShiftOperation(this, dst, src, amount,
|
||||
&TurboAssembler::ShlPair_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i64_sar(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned) {
|
||||
liftoff::Emit64BitShiftOperation(this, dst, src, amount,
|
||||
&TurboAssembler::SarPair_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i64_shr(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned) {
|
||||
liftoff::Emit64BitShiftOperation(this, dst, src, amount,
|
||||
&TurboAssembler::ShrPair_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_ptrsize_add(Register dst, Register lhs,
|
||||
Register rhs) {
|
||||
emit_i32_add(dst, lhs, rhs);
|
||||
|
@ -555,7 +555,7 @@ void LiftoffAssembler::FinishCall(wasm::FunctionSig* sig,
|
||||
LiftoffRegister high_reg = LiftoffRegister::from_code(
|
||||
rc, call_descriptor->GetReturnLocation(1).AsRegister());
|
||||
DCHECK(GetCacheRegList(rc).has(high_reg));
|
||||
return_reg = LiftoffRegister::ForPair(return_reg, high_reg);
|
||||
return_reg = LiftoffRegister::ForPair(return_reg.gp(), high_reg.gp());
|
||||
}
|
||||
DCHECK(!cache_state_.is_used(return_reg));
|
||||
PushRegister(return_type, return_reg);
|
||||
@ -565,6 +565,7 @@ void LiftoffAssembler::FinishCall(wasm::FunctionSig* sig,
|
||||
void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src,
|
||||
ValueType type) {
|
||||
DCHECK_EQ(dst.reg_class(), src.reg_class());
|
||||
DCHECK_NE(dst, src);
|
||||
if (kNeedI64RegPair && dst.is_pair()) {
|
||||
// Use the {StackTransferRecipe} to move pairs, as the registers in the
|
||||
// pairs might overlap.
|
||||
|
@ -140,8 +140,8 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
LiftoffRegister unused_register(RegClass rc,
|
||||
LiftoffRegList pinned = {}) const {
|
||||
if (kNeedI64RegPair && rc == kGpRegPair) {
|
||||
LiftoffRegister low = pinned.set(unused_register(kGpReg, pinned));
|
||||
LiftoffRegister high = unused_register(kGpReg, pinned);
|
||||
Register low = pinned.set(unused_register(kGpReg, pinned)).gp();
|
||||
Register high = unused_register(kGpReg, pinned).gp();
|
||||
return LiftoffRegister::ForPair(low, high);
|
||||
}
|
||||
DCHECK(rc == kGpReg || rc == kFpReg);
|
||||
@ -276,8 +276,8 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
LiftoffRegister GetUnusedRegister(RegClass rc, LiftoffRegList pinned = {}) {
|
||||
if (kNeedI64RegPair && rc == kGpRegPair) {
|
||||
LiftoffRegList candidates = kGpCacheRegList;
|
||||
LiftoffRegister low = pinned.set(GetUnusedRegister(candidates, pinned));
|
||||
LiftoffRegister high = GetUnusedRegister(candidates, pinned);
|
||||
Register low = pinned.set(GetUnusedRegister(candidates, pinned)).gp();
|
||||
Register high = GetUnusedRegister(candidates, pinned).gp();
|
||||
return LiftoffRegister::ForPair(low, high);
|
||||
}
|
||||
DCHECK(rc == kGpReg || rc == kFpReg);
|
||||
@ -370,11 +370,11 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
inline void emit_i32_and(Register dst, Register lhs, Register rhs);
|
||||
inline void emit_i32_or(Register dst, Register lhs, Register rhs);
|
||||
inline void emit_i32_xor(Register dst, Register lhs, Register rhs);
|
||||
inline void emit_i32_shl(Register dst, Register lhs, Register rhs,
|
||||
inline void emit_i32_shl(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned = {});
|
||||
inline void emit_i32_sar(Register dst, Register lhs, Register rhs,
|
||||
inline void emit_i32_sar(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned = {});
|
||||
inline void emit_i32_shr(Register dst, Register lhs, Register rhs,
|
||||
inline void emit_i32_shr(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned = {});
|
||||
|
||||
// i32 unops.
|
||||
@ -382,6 +382,14 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
inline bool emit_i32_ctz(Register dst, Register src);
|
||||
inline bool emit_i32_popcnt(Register dst, Register src);
|
||||
|
||||
// i64 binops.
|
||||
inline void emit_i64_shl(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned = {});
|
||||
inline void emit_i64_sar(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned = {});
|
||||
inline void emit_i64_shr(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned = {});
|
||||
|
||||
inline void emit_ptrsize_add(Register dst, Register lhs, Register rhs);
|
||||
|
||||
// f32 binops.
|
||||
|
@ -242,7 +242,8 @@ class LiftoffCompiler {
|
||||
__ LoadCallerFrameSlot(in_reg, -param_loc.AsCallerFrameSlot(),
|
||||
lowered_type);
|
||||
}
|
||||
reg = pair_idx == 0 ? in_reg : LiftoffRegister::ForPair(reg, in_reg);
|
||||
reg = pair_idx == 0 ? in_reg
|
||||
: LiftoffRegister::ForPair(reg.gp(), in_reg.gp());
|
||||
pinned.set(reg);
|
||||
}
|
||||
__ PushRegister(type, reg);
|
||||
@ -701,12 +702,21 @@ class LiftoffCompiler {
|
||||
[=](LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { \
|
||||
__ emit_f32_set_cond(cond, dst.gp(), lhs.fp(), rhs.fp()); \
|
||||
});
|
||||
#define CASE_SHIFTOP(opcode, fn) \
|
||||
case WasmOpcode::kExpr##opcode: \
|
||||
return EmitMonomorphicBinOp<kWasmI32>( \
|
||||
[=](LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { \
|
||||
__ emit_##fn(dst.gp(), lhs.gp(), rhs.gp(), {}); \
|
||||
});
|
||||
#define CASE_I32_SHIFTOP(opcode, fn) \
|
||||
case WasmOpcode::kExpr##opcode: \
|
||||
return EmitMonomorphicBinOp<kWasmI32>([=](LiftoffRegister dst, \
|
||||
LiftoffRegister src, \
|
||||
LiftoffRegister amount) { \
|
||||
__ emit_##fn(dst.gp(), src.gp(), amount.gp(), {}); \
|
||||
});
|
||||
#define CASE_I64_SHIFTOP(opcode, fn) \
|
||||
case WasmOpcode::kExpr##opcode: \
|
||||
return EmitMonomorphicBinOp<kWasmI64>([=](LiftoffRegister dst, \
|
||||
LiftoffRegister src, \
|
||||
LiftoffRegister amount) { \
|
||||
__ emit_##fn(dst, src, amount.is_pair() ? amount.low_gp() : amount.gp(), \
|
||||
{}); \
|
||||
});
|
||||
#define CASE_CCALL_BINOP(opcode, type, ext_ref_fn) \
|
||||
case WasmOpcode::kExpr##opcode: \
|
||||
return EmitMonomorphicBinOp<kWasmI32>( \
|
||||
@ -740,9 +750,12 @@ class LiftoffCompiler {
|
||||
CASE_F32_CMPOP(F32Gt, kUnsignedGreaterThan)
|
||||
CASE_F32_CMPOP(F32Le, kUnsignedLessEqual)
|
||||
CASE_F32_CMPOP(F32Ge, kUnsignedGreaterEqual)
|
||||
CASE_SHIFTOP(I32Shl, i32_shl)
|
||||
CASE_SHIFTOP(I32ShrS, i32_sar)
|
||||
CASE_SHIFTOP(I32ShrU, i32_shr)
|
||||
CASE_I32_SHIFTOP(I32Shl, i32_shl)
|
||||
CASE_I32_SHIFTOP(I32ShrS, i32_sar)
|
||||
CASE_I32_SHIFTOP(I32ShrU, i32_shr)
|
||||
CASE_I64_SHIFTOP(I64Shl, i64_shl)
|
||||
CASE_I64_SHIFTOP(I64ShrS, i64_sar)
|
||||
CASE_I64_SHIFTOP(I64ShrU, i64_shr)
|
||||
CASE_CCALL_BINOP(I32Rol, I32, wasm_word32_rol)
|
||||
CASE_CCALL_BINOP(I32Ror, I32, wasm_word32_ror)
|
||||
CASE_FLOAT_BINOP(F32Add, F32, f32_add)
|
||||
@ -760,7 +773,8 @@ class LiftoffCompiler {
|
||||
#undef CASE_FLOAT_BINOP
|
||||
#undef CASE_I32_CMPOP
|
||||
#undef CASE_F32_CMPOP
|
||||
#undef CASE_SHIFTOP
|
||||
#undef CASE_I32_SHIFTOP
|
||||
#undef CASE_I64_SHIFTOP
|
||||
#undef CASE_CCALL_BINOP
|
||||
}
|
||||
|
||||
|
@ -103,11 +103,10 @@ class LiftoffRegister {
|
||||
}
|
||||
}
|
||||
|
||||
static LiftoffRegister ForPair(LiftoffRegister low, LiftoffRegister high) {
|
||||
static LiftoffRegister ForPair(Register low, Register high) {
|
||||
DCHECK(kNeedI64RegPair);
|
||||
DCHECK_NE(low, high);
|
||||
storage_t combined_code = low.gp().code() |
|
||||
high.gp().code() << kBitsPerGpRegCode |
|
||||
storage_t combined_code = low.code() | high.code() << kBitsPerGpRegCode |
|
||||
1 << (2 * kBitsPerGpRegCode);
|
||||
return LiftoffRegister(combined_code);
|
||||
}
|
||||
|
@ -293,9 +293,8 @@ void LiftoffAssembler::MoveToReturnRegister(LiftoffRegister reg,
|
||||
// TODO(wasm): Extract the destination register from the CallDescriptor.
|
||||
// TODO(wasm): Add multi-return support.
|
||||
LiftoffRegister dst =
|
||||
reg.is_pair()
|
||||
? LiftoffRegister::ForPair(LiftoffRegister(v0), LiftoffRegister(v1))
|
||||
: reg.is_gp() ? LiftoffRegister(v0) : LiftoffRegister(f2);
|
||||
reg.is_pair() ? LiftoffRegister::ForPair(v0, v1)
|
||||
: reg.is_gp() ? LiftoffRegister(v0) : LiftoffRegister(f2);
|
||||
if (reg != dst) Move(dst, reg, type);
|
||||
}
|
||||
|
||||
@ -429,10 +428,10 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#define I32_SHIFTOP(name, instruction) \
|
||||
void LiftoffAssembler::emit_i32_##name( \
|
||||
Register dst, Register lhs, Register rhs, LiftoffRegList pinned) { \
|
||||
instruction(dst, lhs, rhs); \
|
||||
#define I32_SHIFTOP(name, instruction) \
|
||||
void LiftoffAssembler::emit_i32_##name( \
|
||||
Register dst, Register src, Register amount, LiftoffRegList pinned) { \
|
||||
instruction(dst, src, amount); \
|
||||
}
|
||||
|
||||
I32_SHIFTOP(shl, sllv)
|
||||
@ -441,6 +440,19 @@ I32_SHIFTOP(shr, srlv)
|
||||
|
||||
#undef I32_SHIFTOP
|
||||
|
||||
#define UNIMPLEMENTED_I64_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_i64_##name(LiftoffRegister dst, \
|
||||
LiftoffRegister src, Register amount, \
|
||||
LiftoffRegList pinned) { \
|
||||
BAILOUT("i64 shiftop"); \
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_I64_SHIFTOP(shl)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(sar)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(shr)
|
||||
|
||||
#undef I32_SHIFTOP
|
||||
|
||||
#define FP_BINOP(name, instruction) \
|
||||
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
|
||||
DoubleRegister rhs) { \
|
||||
|
@ -375,10 +375,10 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#define I32_SHIFTOP(name, instruction) \
|
||||
void LiftoffAssembler::emit_i32_##name( \
|
||||
Register dst, Register lhs, Register rhs, LiftoffRegList pinned) { \
|
||||
instruction(dst, lhs, rhs); \
|
||||
#define I32_SHIFTOP(name, instruction) \
|
||||
void LiftoffAssembler::emit_i32_##name( \
|
||||
Register dst, Register src, Register amount, LiftoffRegList pinned) { \
|
||||
instruction(dst, src, amount); \
|
||||
}
|
||||
|
||||
I32_SHIFTOP(shl, sllv)
|
||||
@ -387,6 +387,19 @@ I32_SHIFTOP(shr, srlv)
|
||||
|
||||
#undef I32_SHIFTOP
|
||||
|
||||
#define UNIMPLEMENTED_I64_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_i64_##name(LiftoffRegister dst, \
|
||||
LiftoffRegister src, Register amount, \
|
||||
LiftoffRegList pinned) { \
|
||||
BAILOUT("i64 shiftop"); \
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_I64_SHIFTOP(shl)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(sar)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(shr)
|
||||
|
||||
#undef I32_SHIFTOP
|
||||
|
||||
#define FP_BINOP(name, instruction) \
|
||||
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
|
||||
DoubleRegister rhs) { \
|
||||
|
@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
|
||||
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
|
||||
BAILOUT("fp unop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \
|
||||
LiftoffRegList pinned) { \
|
||||
BAILOUT("shiftop"); \
|
||||
#define UNIMPLEMENTED_I32_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i32 shiftop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_I64_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(LiftoffRegister dst, LiftoffRegister src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i64 shiftop"); \
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_GP_BINOP(i32_add)
|
||||
@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_and)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_or)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_xor)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shl)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_sar)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shr)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_clz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_ctz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_popcnt)
|
||||
@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
|
||||
#undef UNIMPLEMENTED_GP_UNOP
|
||||
#undef UNIMPLEMENTED_FP_BINOP
|
||||
#undef UNIMPLEMENTED_FP_UNOP
|
||||
#undef UNIMPLEMENTED_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I32_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I64_SHIFTOP
|
||||
|
||||
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
|
||||
LiftoffRegister dst,
|
||||
|
@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
|
||||
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
|
||||
BAILOUT("fp unop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \
|
||||
LiftoffRegList pinned) { \
|
||||
BAILOUT("shiftop"); \
|
||||
#define UNIMPLEMENTED_I32_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(Register dst, Register src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i32 shiftop"); \
|
||||
}
|
||||
#define UNIMPLEMENTED_I64_SHIFTOP(name) \
|
||||
void LiftoffAssembler::emit_##name(LiftoffRegister dst, LiftoffRegister src, \
|
||||
Register amount, LiftoffRegList pinned) { \
|
||||
BAILOUT("i64 shiftop"); \
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_GP_BINOP(i32_add)
|
||||
@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_and)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_or)
|
||||
UNIMPLEMENTED_GP_BINOP(i32_xor)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
|
||||
UNIMPLEMENTED_I32_SHIFTOP(i32_shr)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shl)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_sar)
|
||||
UNIMPLEMENTED_I64_SHIFTOP(i64_shr)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_clz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_ctz)
|
||||
UNIMPLEMENTED_GP_UNOP(i32_popcnt)
|
||||
@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
|
||||
#undef UNIMPLEMENTED_GP_UNOP
|
||||
#undef UNIMPLEMENTED_FP_BINOP
|
||||
#undef UNIMPLEMENTED_FP_UNOP
|
||||
#undef UNIMPLEMENTED_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I32_SHIFTOP
|
||||
#undef UNIMPLEMENTED_I64_SHIFTOP
|
||||
|
||||
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
|
||||
LiftoffRegister dst,
|
||||
|
@ -403,33 +403,34 @@ COMMUTATIVE_I32_BINOP(xor, xor)
|
||||
#undef COMMUTATIVE_I32_BINOP
|
||||
|
||||
namespace liftoff {
|
||||
template <ValueType type>
|
||||
inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
|
||||
Register lhs, Register rhs,
|
||||
Register src, Register amount,
|
||||
void (Assembler::*emit_shift)(Register),
|
||||
LiftoffRegList pinned) {
|
||||
// If dst is rcx, compute into the scratch register first, then move to rcx.
|
||||
if (dst == rcx) {
|
||||
assm->movl(kScratchRegister, lhs);
|
||||
if (rhs != rcx) assm->movl(rcx, rhs);
|
||||
assm->Move(kScratchRegister, src, type);
|
||||
if (amount != rcx) assm->Move(rcx, amount, type);
|
||||
(assm->*emit_shift)(kScratchRegister);
|
||||
assm->movl(rcx, kScratchRegister);
|
||||
assm->Move(rcx, kScratchRegister, type);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move rhs into rcx. If rcx is in use, move its content into the scratch
|
||||
// register. If lhs is rcx, lhs is now the scratch register.
|
||||
// Move amount into rcx. If rcx is in use, move its content into the scratch
|
||||
// register. If src is rcx, src is now the scratch register.
|
||||
bool use_scratch = false;
|
||||
if (rhs != rcx) {
|
||||
use_scratch = lhs == rcx ||
|
||||
if (amount != rcx) {
|
||||
use_scratch = src == rcx ||
|
||||
assm->cache_state()->is_used(LiftoffRegister(rcx)) ||
|
||||
pinned.has(LiftoffRegister(rcx));
|
||||
if (use_scratch) assm->movq(kScratchRegister, rcx);
|
||||
if (lhs == rcx) lhs = kScratchRegister;
|
||||
assm->movl(rcx, rhs);
|
||||
if (src == rcx) src = kScratchRegister;
|
||||
assm->Move(rcx, amount, type);
|
||||
}
|
||||
|
||||
// Do the actual shift.
|
||||
if (dst != lhs) assm->movl(dst, lhs);
|
||||
if (dst != src) assm->Move(dst, src, type);
|
||||
(assm->*emit_shift)(dst);
|
||||
|
||||
// Restore rcx if needed.
|
||||
@ -437,19 +438,22 @@ inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
|
||||
}
|
||||
} // namespace liftoff
|
||||
|
||||
void LiftoffAssembler::emit_i32_shl(Register dst, Register lhs, Register rhs,
|
||||
void LiftoffAssembler::emit_i32_shl(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation(this, dst, lhs, rhs, &Assembler::shll_cl, pinned);
|
||||
liftoff::EmitShiftOperation<kWasmI32>(this, dst, src, amount,
|
||||
&Assembler::shll_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i32_sar(Register dst, Register lhs, Register rhs,
|
||||
void LiftoffAssembler::emit_i32_sar(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation(this, dst, lhs, rhs, &Assembler::sarl_cl, pinned);
|
||||
liftoff::EmitShiftOperation<kWasmI32>(this, dst, src, amount,
|
||||
&Assembler::sarl_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i32_shr(Register dst, Register lhs, Register rhs,
|
||||
void LiftoffAssembler::emit_i32_shr(Register dst, Register src, Register amount,
|
||||
LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation(this, dst, lhs, rhs, &Assembler::shrl_cl, pinned);
|
||||
liftoff::EmitShiftOperation<kWasmI32>(this, dst, src, amount,
|
||||
&Assembler::shrl_cl, pinned);
|
||||
}
|
||||
|
||||
bool LiftoffAssembler::emit_i32_clz(Register dst, Register src) {
|
||||
@ -493,6 +497,24 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i64_shl(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation<kWasmI64>(this, dst.gp(), src.gp(), amount,
|
||||
&Assembler::shlq_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i64_sar(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation<kWasmI64>(this, dst.gp(), src.gp(), amount,
|
||||
&Assembler::sarq_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_i64_shr(LiftoffRegister dst, LiftoffRegister src,
|
||||
Register amount, LiftoffRegList pinned) {
|
||||
liftoff::EmitShiftOperation<kWasmI64>(this, dst.gp(), src.gp(), amount,
|
||||
&Assembler::shrq_cl, pinned);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::emit_ptrsize_add(Register dst, Register lhs,
|
||||
Register rhs) {
|
||||
if (lhs != dst) {
|
||||
|
Loading…
Reference in New Issue
Block a user