[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:
Clemens Hammacher 2018-03-19 11:57:20 +01:00 committed by Commit Bot
parent dfc2805ccf
commit d9fd12cfb3
13 changed files with 282 additions and 104 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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
}

View File

@ -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);
}

View File

@ -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) { \

View File

@ -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) { \

View File

@ -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,

View File

@ -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,

View File

@ -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) {