Commit d9fd12cf authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[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: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52022}
parent dfc2805c
...@@ -179,7 +179,7 @@ class TurboAssembler : public Assembler { ...@@ -179,7 +179,7 @@ class TurboAssembler : public Assembler {
void ShlPair(Register high, Register low, uint8_t imm8); void ShlPair(Register high, Register low, uint8_t imm8);
void ShlPair_cl(Register high, Register low); void ShlPair_cl(Register high, Register low);
void ShrPair(Register high, Register low, uint8_t imm8); 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(Register high, Register low, uint8_t imm8);
void SarPair_cl(Register high, Register low); void SarPair_cl(Register high, Register low);
......
...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) { ...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
BAILOUT("fp unop"); \ BAILOUT("fp unop"); \
} }
#define UNIMPLEMENTED_SHIFTOP(name) \ #define UNIMPLEMENTED_I32_SHIFTOP(name) \
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \ void LiftoffAssembler::emit_##name(Register dst, Register src, \
LiftoffRegList pinned) { \ Register amount, LiftoffRegList pinned) { \
BAILOUT("shiftop"); \ 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) UNIMPLEMENTED_GP_BINOP(i32_add)
...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul) ...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
UNIMPLEMENTED_GP_BINOP(i32_and) UNIMPLEMENTED_GP_BINOP(i32_and)
UNIMPLEMENTED_GP_BINOP(i32_or) UNIMPLEMENTED_GP_BINOP(i32_or)
UNIMPLEMENTED_GP_BINOP(i32_xor) UNIMPLEMENTED_GP_BINOP(i32_xor)
UNIMPLEMENTED_SHIFTOP(i32_shl) UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
UNIMPLEMENTED_SHIFTOP(i32_sar) UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
UNIMPLEMENTED_SHIFTOP(i32_shr) 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_clz)
UNIMPLEMENTED_GP_UNOP(i32_ctz) UNIMPLEMENTED_GP_UNOP(i32_ctz)
UNIMPLEMENTED_GP_UNOP(i32_popcnt) UNIMPLEMENTED_GP_UNOP(i32_popcnt)
...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt) ...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
#undef UNIMPLEMENTED_GP_UNOP #undef UNIMPLEMENTED_GP_UNOP
#undef UNIMPLEMENTED_FP_BINOP #undef UNIMPLEMENTED_FP_BINOP
#undef UNIMPLEMENTED_FP_UNOP #undef UNIMPLEMENTED_FP_UNOP
#undef UNIMPLEMENTED_SHIFTOP #undef UNIMPLEMENTED_I32_SHIFTOP
#undef UNIMPLEMENTED_I64_SHIFTOP
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
LiftoffRegister dst, LiftoffRegister dst,
......
...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) { ...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
BAILOUT("fp unop"); \ BAILOUT("fp unop"); \
} }
#define UNIMPLEMENTED_SHIFTOP(name) \ #define UNIMPLEMENTED_I32_SHIFTOP(name) \
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \ void LiftoffAssembler::emit_##name(Register dst, Register src, \
LiftoffRegList pinned) { \ Register amount, LiftoffRegList pinned) { \
BAILOUT("shiftop"); \ 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) UNIMPLEMENTED_GP_BINOP(i32_add)
...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul) ...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
UNIMPLEMENTED_GP_BINOP(i32_and) UNIMPLEMENTED_GP_BINOP(i32_and)
UNIMPLEMENTED_GP_BINOP(i32_or) UNIMPLEMENTED_GP_BINOP(i32_or)
UNIMPLEMENTED_GP_BINOP(i32_xor) UNIMPLEMENTED_GP_BINOP(i32_xor)
UNIMPLEMENTED_SHIFTOP(i32_shl) UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
UNIMPLEMENTED_SHIFTOP(i32_sar) UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
UNIMPLEMENTED_SHIFTOP(i32_shr) 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_clz)
UNIMPLEMENTED_GP_UNOP(i32_ctz) UNIMPLEMENTED_GP_UNOP(i32_ctz)
UNIMPLEMENTED_GP_UNOP(i32_popcnt) UNIMPLEMENTED_GP_UNOP(i32_popcnt)
...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt) ...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
#undef UNIMPLEMENTED_GP_UNOP #undef UNIMPLEMENTED_GP_UNOP
#undef UNIMPLEMENTED_FP_BINOP #undef UNIMPLEMENTED_FP_BINOP
#undef UNIMPLEMENTED_FP_UNOP #undef UNIMPLEMENTED_FP_UNOP
#undef UNIMPLEMENTED_SHIFTOP #undef UNIMPLEMENTED_I32_SHIFTOP
#undef UNIMPLEMENTED_I64_SHIFTOP
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
LiftoffRegister dst, LiftoffRegister dst,
......
...@@ -318,10 +318,9 @@ void LiftoffAssembler::MoveToReturnRegister(LiftoffRegister reg, ...@@ -318,10 +318,9 @@ void LiftoffAssembler::MoveToReturnRegister(LiftoffRegister reg,
ValueType type) { ValueType type) {
// TODO(wasm): Extract the destination register from the CallDescriptor. // TODO(wasm): Extract the destination register from the CallDescriptor.
// TODO(wasm): Add multi-return support. // TODO(wasm): Add multi-return support.
LiftoffRegister dst = LiftoffRegister dst = reg.is_pair() ? LiftoffRegister::ForPair(eax, edx)
reg.is_pair() : reg.is_gp() ? LiftoffRegister(eax)
? LiftoffRegister::ForPair(LiftoffRegister(eax), LiftoffRegister(edx)) : LiftoffRegister(xmm1);
: reg.is_gp() ? LiftoffRegister(eax) : LiftoffRegister(xmm1);
if (reg != dst) Move(dst, reg, type); if (reg != dst) Move(dst, reg, type);
} }
...@@ -451,37 +450,37 @@ COMMUTATIVE_I32_BINOP(xor, xor_) ...@@ -451,37 +450,37 @@ COMMUTATIVE_I32_BINOP(xor, xor_)
namespace liftoff { namespace liftoff {
inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst, inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
Register lhs, Register rhs, Register src, Register amount,
void (Assembler::*emit_shift)(Register), void (Assembler::*emit_shift)(Register),
LiftoffRegList pinned) { LiftoffRegList pinned) {
pinned.set(dst); pinned.set(dst);
pinned.set(lhs); pinned.set(src);
pinned.set(rhs); pinned.set(amount);
// If dst is ecx, compute into a tmp register first, then move to ecx. // If dst is ecx, compute into a tmp register first, then move to ecx.
if (dst == ecx) { if (dst == ecx) {
Register tmp = assm->GetUnusedRegister(kGpReg, pinned).gp(); Register tmp = assm->GetUnusedRegister(kGpReg, pinned).gp();
assm->mov(tmp, lhs); assm->mov(tmp, src);
if (rhs != ecx) assm->mov(ecx, rhs); if (amount != ecx) assm->mov(ecx, amount);
(assm->*emit_shift)(tmp); (assm->*emit_shift)(tmp);
assm->mov(ecx, tmp); assm->mov(ecx, tmp);
return; return;
} }
// Move rhs into ecx. If ecx is in use, move its content to a tmp register // Move amount 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. // first. If src is ecx, src is now the tmp register.
Register tmp_reg = no_reg; Register tmp_reg = no_reg;
if (rhs != ecx) { if (amount != ecx) {
if (assm->cache_state()->is_used(LiftoffRegister(ecx)) || if (assm->cache_state()->is_used(LiftoffRegister(ecx)) ||
pinned.has(LiftoffRegister(ecx))) { pinned.has(LiftoffRegister(ecx))) {
tmp_reg = assm->GetUnusedRegister(kGpReg, pinned).gp(); tmp_reg = assm->GetUnusedRegister(kGpReg, pinned).gp();
assm->mov(tmp_reg, ecx); 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. // Do the actual shift.
if (dst != lhs) assm->mov(dst, lhs); if (dst != src) assm->mov(dst, src);
(assm->*emit_shift)(dst); (assm->*emit_shift)(dst);
// Restore ecx if needed. // Restore ecx if needed.
...@@ -489,19 +488,22 @@ inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst, ...@@ -489,19 +488,22 @@ inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
} }
} // namespace liftoff } // 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) { 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) { 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) { 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) { bool LiftoffAssembler::emit_i32_clz(Register dst, Register src) {
...@@ -545,6 +547,77 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { ...@@ -545,6 +547,77 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
return true; 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, void LiftoffAssembler::emit_ptrsize_add(Register dst, Register lhs,
Register rhs) { Register rhs) {
emit_i32_add(dst, lhs, rhs); emit_i32_add(dst, lhs, rhs);
......
...@@ -555,7 +555,7 @@ void LiftoffAssembler::FinishCall(wasm::FunctionSig* sig, ...@@ -555,7 +555,7 @@ void LiftoffAssembler::FinishCall(wasm::FunctionSig* sig,
LiftoffRegister high_reg = LiftoffRegister::from_code( LiftoffRegister high_reg = LiftoffRegister::from_code(
rc, call_descriptor->GetReturnLocation(1).AsRegister()); rc, call_descriptor->GetReturnLocation(1).AsRegister());
DCHECK(GetCacheRegList(rc).has(high_reg)); 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)); DCHECK(!cache_state_.is_used(return_reg));
PushRegister(return_type, return_reg); PushRegister(return_type, return_reg);
...@@ -565,6 +565,7 @@ void LiftoffAssembler::FinishCall(wasm::FunctionSig* sig, ...@@ -565,6 +565,7 @@ void LiftoffAssembler::FinishCall(wasm::FunctionSig* sig,
void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src, void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src,
ValueType type) { ValueType type) {
DCHECK_EQ(dst.reg_class(), src.reg_class()); DCHECK_EQ(dst.reg_class(), src.reg_class());
DCHECK_NE(dst, src);
if (kNeedI64RegPair && dst.is_pair()) { if (kNeedI64RegPair && dst.is_pair()) {
// Use the {StackTransferRecipe} to move pairs, as the registers in the // Use the {StackTransferRecipe} to move pairs, as the registers in the
// pairs might overlap. // pairs might overlap.
......
...@@ -140,8 +140,8 @@ class LiftoffAssembler : public TurboAssembler { ...@@ -140,8 +140,8 @@ class LiftoffAssembler : public TurboAssembler {
LiftoffRegister unused_register(RegClass rc, LiftoffRegister unused_register(RegClass rc,
LiftoffRegList pinned = {}) const { LiftoffRegList pinned = {}) const {
if (kNeedI64RegPair && rc == kGpRegPair) { if (kNeedI64RegPair && rc == kGpRegPair) {
LiftoffRegister low = pinned.set(unused_register(kGpReg, pinned)); Register low = pinned.set(unused_register(kGpReg, pinned)).gp();
LiftoffRegister high = unused_register(kGpReg, pinned); Register high = unused_register(kGpReg, pinned).gp();
return LiftoffRegister::ForPair(low, high); return LiftoffRegister::ForPair(low, high);
} }
DCHECK(rc == kGpReg || rc == kFpReg); DCHECK(rc == kGpReg || rc == kFpReg);
...@@ -276,8 +276,8 @@ class LiftoffAssembler : public TurboAssembler { ...@@ -276,8 +276,8 @@ class LiftoffAssembler : public TurboAssembler {
LiftoffRegister GetUnusedRegister(RegClass rc, LiftoffRegList pinned = {}) { LiftoffRegister GetUnusedRegister(RegClass rc, LiftoffRegList pinned = {}) {
if (kNeedI64RegPair && rc == kGpRegPair) { if (kNeedI64RegPair && rc == kGpRegPair) {
LiftoffRegList candidates = kGpCacheRegList; LiftoffRegList candidates = kGpCacheRegList;
LiftoffRegister low = pinned.set(GetUnusedRegister(candidates, pinned)); Register low = pinned.set(GetUnusedRegister(candidates, pinned)).gp();
LiftoffRegister high = GetUnusedRegister(candidates, pinned); Register high = GetUnusedRegister(candidates, pinned).gp();
return LiftoffRegister::ForPair(low, high); return LiftoffRegister::ForPair(low, high);
} }
DCHECK(rc == kGpReg || rc == kFpReg); DCHECK(rc == kGpReg || rc == kFpReg);
...@@ -370,11 +370,11 @@ class LiftoffAssembler : public TurboAssembler { ...@@ -370,11 +370,11 @@ class LiftoffAssembler : public TurboAssembler {
inline void emit_i32_and(Register dst, Register lhs, Register rhs); 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_or(Register dst, Register lhs, Register rhs);
inline void emit_i32_xor(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 = {}); 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 = {}); 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 = {}); LiftoffRegList pinned = {});
// i32 unops. // i32 unops.
...@@ -382,6 +382,14 @@ class LiftoffAssembler : public TurboAssembler { ...@@ -382,6 +382,14 @@ class LiftoffAssembler : public TurboAssembler {
inline bool emit_i32_ctz(Register dst, Register src); inline bool emit_i32_ctz(Register dst, Register src);
inline bool emit_i32_popcnt(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); inline void emit_ptrsize_add(Register dst, Register lhs, Register rhs);
// f32 binops. // f32 binops.
......
...@@ -242,7 +242,8 @@ class LiftoffCompiler { ...@@ -242,7 +242,8 @@ class LiftoffCompiler {
__ LoadCallerFrameSlot(in_reg, -param_loc.AsCallerFrameSlot(), __ LoadCallerFrameSlot(in_reg, -param_loc.AsCallerFrameSlot(),
lowered_type); 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); pinned.set(reg);
} }
__ PushRegister(type, reg); __ PushRegister(type, reg);
...@@ -701,12 +702,21 @@ class LiftoffCompiler { ...@@ -701,12 +702,21 @@ class LiftoffCompiler {
[=](LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { \ [=](LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { \
__ emit_f32_set_cond(cond, dst.gp(), lhs.fp(), rhs.fp()); \ __ emit_f32_set_cond(cond, dst.gp(), lhs.fp(), rhs.fp()); \
}); });
#define CASE_SHIFTOP(opcode, fn) \ #define CASE_I32_SHIFTOP(opcode, fn) \
case WasmOpcode::kExpr##opcode: \ case WasmOpcode::kExpr##opcode: \
return EmitMonomorphicBinOp<kWasmI32>( \ return EmitMonomorphicBinOp<kWasmI32>([=](LiftoffRegister dst, \
[=](LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { \ LiftoffRegister src, \
__ emit_##fn(dst.gp(), lhs.gp(), rhs.gp(), {}); \ 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) \ #define CASE_CCALL_BINOP(opcode, type, ext_ref_fn) \
case WasmOpcode::kExpr##opcode: \ case WasmOpcode::kExpr##opcode: \
return EmitMonomorphicBinOp<kWasmI32>( \ return EmitMonomorphicBinOp<kWasmI32>( \
...@@ -740,9 +750,12 @@ class LiftoffCompiler { ...@@ -740,9 +750,12 @@ class LiftoffCompiler {
CASE_F32_CMPOP(F32Gt, kUnsignedGreaterThan) CASE_F32_CMPOP(F32Gt, kUnsignedGreaterThan)
CASE_F32_CMPOP(F32Le, kUnsignedLessEqual) CASE_F32_CMPOP(F32Le, kUnsignedLessEqual)
CASE_F32_CMPOP(F32Ge, kUnsignedGreaterEqual) CASE_F32_CMPOP(F32Ge, kUnsignedGreaterEqual)
CASE_SHIFTOP(I32Shl, i32_shl) CASE_I32_SHIFTOP(I32Shl, i32_shl)
CASE_SHIFTOP(I32ShrS, i32_sar) CASE_I32_SHIFTOP(I32ShrS, i32_sar)
CASE_SHIFTOP(I32ShrU, i32_shr) 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(I32Rol, I32, wasm_word32_rol)
CASE_CCALL_BINOP(I32Ror, I32, wasm_word32_ror) CASE_CCALL_BINOP(I32Ror, I32, wasm_word32_ror)
CASE_FLOAT_BINOP(F32Add, F32, f32_add) CASE_FLOAT_BINOP(F32Add, F32, f32_add)
...@@ -760,7 +773,8 @@ class LiftoffCompiler { ...@@ -760,7 +773,8 @@ class LiftoffCompiler {
#undef CASE_FLOAT_BINOP #undef CASE_FLOAT_BINOP
#undef CASE_I32_CMPOP #undef CASE_I32_CMPOP
#undef CASE_F32_CMPOP #undef CASE_F32_CMPOP
#undef CASE_SHIFTOP #undef CASE_I32_SHIFTOP
#undef CASE_I64_SHIFTOP
#undef CASE_CCALL_BINOP #undef CASE_CCALL_BINOP
} }
......
...@@ -103,11 +103,10 @@ class LiftoffRegister { ...@@ -103,11 +103,10 @@ class LiftoffRegister {
} }
} }
static LiftoffRegister ForPair(LiftoffRegister low, LiftoffRegister high) { static LiftoffRegister ForPair(Register low, Register high) {
DCHECK(kNeedI64RegPair); DCHECK(kNeedI64RegPair);
DCHECK_NE(low, high); DCHECK_NE(low, high);
storage_t combined_code = low.gp().code() | storage_t combined_code = low.code() | high.code() << kBitsPerGpRegCode |
high.gp().code() << kBitsPerGpRegCode |
1 << (2 * kBitsPerGpRegCode); 1 << (2 * kBitsPerGpRegCode);
return LiftoffRegister(combined_code); return LiftoffRegister(combined_code);
} }
......
...@@ -293,9 +293,8 @@ void LiftoffAssembler::MoveToReturnRegister(LiftoffRegister reg, ...@@ -293,9 +293,8 @@ void LiftoffAssembler::MoveToReturnRegister(LiftoffRegister reg,
// TODO(wasm): Extract the destination register from the CallDescriptor. // TODO(wasm): Extract the destination register from the CallDescriptor.
// TODO(wasm): Add multi-return support. // TODO(wasm): Add multi-return support.
LiftoffRegister dst = LiftoffRegister dst =
reg.is_pair() reg.is_pair() ? LiftoffRegister::ForPair(v0, v1)
? LiftoffRegister::ForPair(LiftoffRegister(v0), LiftoffRegister(v1)) : reg.is_gp() ? LiftoffRegister(v0) : LiftoffRegister(f2);
: reg.is_gp() ? LiftoffRegister(v0) : LiftoffRegister(f2);
if (reg != dst) Move(dst, reg, type); if (reg != dst) Move(dst, reg, type);
} }
...@@ -429,10 +428,10 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { ...@@ -429,10 +428,10 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
return true; return true;
} }
#define I32_SHIFTOP(name, instruction) \ #define I32_SHIFTOP(name, instruction) \
void LiftoffAssembler::emit_i32_##name( \ void LiftoffAssembler::emit_i32_##name( \
Register dst, Register lhs, Register rhs, LiftoffRegList pinned) { \ Register dst, Register src, Register amount, LiftoffRegList pinned) { \
instruction(dst, lhs, rhs); \ instruction(dst, src, amount); \
} }
I32_SHIFTOP(shl, sllv) I32_SHIFTOP(shl, sllv)
...@@ -441,6 +440,19 @@ I32_SHIFTOP(shr, srlv) ...@@ -441,6 +440,19 @@ I32_SHIFTOP(shr, srlv)
#undef I32_SHIFTOP #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) \ #define FP_BINOP(name, instruction) \
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
DoubleRegister rhs) { \ DoubleRegister rhs) { \
......
...@@ -375,10 +375,10 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { ...@@ -375,10 +375,10 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
return true; return true;
} }
#define I32_SHIFTOP(name, instruction) \ #define I32_SHIFTOP(name, instruction) \
void LiftoffAssembler::emit_i32_##name( \ void LiftoffAssembler::emit_i32_##name( \
Register dst, Register lhs, Register rhs, LiftoffRegList pinned) { \ Register dst, Register src, Register amount, LiftoffRegList pinned) { \
instruction(dst, lhs, rhs); \ instruction(dst, src, amount); \
} }
I32_SHIFTOP(shl, sllv) I32_SHIFTOP(shl, sllv)
...@@ -387,6 +387,19 @@ I32_SHIFTOP(shr, srlv) ...@@ -387,6 +387,19 @@ I32_SHIFTOP(shr, srlv)
#undef I32_SHIFTOP #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) \ #define FP_BINOP(name, instruction) \
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
DoubleRegister rhs) { \ DoubleRegister rhs) { \
......
...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) { ...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
BAILOUT("fp unop"); \ BAILOUT("fp unop"); \
} }
#define UNIMPLEMENTED_SHIFTOP(name) \ #define UNIMPLEMENTED_I32_SHIFTOP(name) \
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \ void LiftoffAssembler::emit_##name(Register dst, Register src, \
LiftoffRegList pinned) { \ Register amount, LiftoffRegList pinned) { \
BAILOUT("shiftop"); \ 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) UNIMPLEMENTED_GP_BINOP(i32_add)
...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul) ...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
UNIMPLEMENTED_GP_BINOP(i32_and) UNIMPLEMENTED_GP_BINOP(i32_and)
UNIMPLEMENTED_GP_BINOP(i32_or) UNIMPLEMENTED_GP_BINOP(i32_or)
UNIMPLEMENTED_GP_BINOP(i32_xor) UNIMPLEMENTED_GP_BINOP(i32_xor)
UNIMPLEMENTED_SHIFTOP(i32_shl) UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
UNIMPLEMENTED_SHIFTOP(i32_sar) UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
UNIMPLEMENTED_SHIFTOP(i32_shr) 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_clz)
UNIMPLEMENTED_GP_UNOP(i32_ctz) UNIMPLEMENTED_GP_UNOP(i32_ctz)
UNIMPLEMENTED_GP_UNOP(i32_popcnt) UNIMPLEMENTED_GP_UNOP(i32_popcnt)
...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt) ...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
#undef UNIMPLEMENTED_GP_UNOP #undef UNIMPLEMENTED_GP_UNOP
#undef UNIMPLEMENTED_FP_BINOP #undef UNIMPLEMENTED_FP_BINOP
#undef UNIMPLEMENTED_FP_UNOP #undef UNIMPLEMENTED_FP_UNOP
#undef UNIMPLEMENTED_SHIFTOP #undef UNIMPLEMENTED_I32_SHIFTOP
#undef UNIMPLEMENTED_I64_SHIFTOP
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
LiftoffRegister dst, LiftoffRegister dst,
......
...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) { ...@@ -117,10 +117,15 @@ void LiftoffAssembler::FillI64Half(Register, uint32_t half_index) {
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \
BAILOUT("fp unop"); \ BAILOUT("fp unop"); \
} }
#define UNIMPLEMENTED_SHIFTOP(name) \ #define UNIMPLEMENTED_I32_SHIFTOP(name) \
void LiftoffAssembler::emit_##name(Register dst, Register lhs, Register rhs, \ void LiftoffAssembler::emit_##name(Register dst, Register src, \
LiftoffRegList pinned) { \ Register amount, LiftoffRegList pinned) { \
BAILOUT("shiftop"); \ 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) UNIMPLEMENTED_GP_BINOP(i32_add)
...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul) ...@@ -129,9 +134,12 @@ UNIMPLEMENTED_GP_BINOP(i32_mul)
UNIMPLEMENTED_GP_BINOP(i32_and) UNIMPLEMENTED_GP_BINOP(i32_and)
UNIMPLEMENTED_GP_BINOP(i32_or) UNIMPLEMENTED_GP_BINOP(i32_or)
UNIMPLEMENTED_GP_BINOP(i32_xor) UNIMPLEMENTED_GP_BINOP(i32_xor)
UNIMPLEMENTED_SHIFTOP(i32_shl) UNIMPLEMENTED_I32_SHIFTOP(i32_shl)
UNIMPLEMENTED_SHIFTOP(i32_sar) UNIMPLEMENTED_I32_SHIFTOP(i32_sar)
UNIMPLEMENTED_SHIFTOP(i32_shr) 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_clz)
UNIMPLEMENTED_GP_UNOP(i32_ctz) UNIMPLEMENTED_GP_UNOP(i32_ctz)
UNIMPLEMENTED_GP_UNOP(i32_popcnt) UNIMPLEMENTED_GP_UNOP(i32_popcnt)
...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt) ...@@ -153,7 +161,8 @@ UNIMPLEMENTED_FP_UNOP(f64_sqrt)
#undef UNIMPLEMENTED_GP_UNOP #undef UNIMPLEMENTED_GP_UNOP
#undef UNIMPLEMENTED_FP_BINOP #undef UNIMPLEMENTED_FP_BINOP
#undef UNIMPLEMENTED_FP_UNOP #undef UNIMPLEMENTED_FP_UNOP
#undef UNIMPLEMENTED_SHIFTOP #undef UNIMPLEMENTED_I32_SHIFTOP
#undef UNIMPLEMENTED_I64_SHIFTOP
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
LiftoffRegister dst, LiftoffRegister dst,
......
...@@ -403,33 +403,34 @@ COMMUTATIVE_I32_BINOP(xor, xor) ...@@ -403,33 +403,34 @@ COMMUTATIVE_I32_BINOP(xor, xor)
#undef COMMUTATIVE_I32_BINOP #undef COMMUTATIVE_I32_BINOP
namespace liftoff { namespace liftoff {
template <ValueType type>
inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst, inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
Register lhs, Register rhs, Register src, Register amount,
void (Assembler::*emit_shift)(Register), void (Assembler::*emit_shift)(Register),
LiftoffRegList pinned) { LiftoffRegList pinned) {
// If dst is rcx, compute into the scratch register first, then move to rcx. // If dst is rcx, compute into the scratch register first, then move to rcx.
if (dst == rcx) { if (dst == rcx) {
assm->movl(kScratchRegister, lhs); assm->Move(kScratchRegister, src, type);
if (rhs != rcx) assm->movl(rcx, rhs); if (amount != rcx) assm->Move(rcx, amount, type);
(assm->*emit_shift)(kScratchRegister); (assm->*emit_shift)(kScratchRegister);
assm->movl(rcx, kScratchRegister); assm->Move(rcx, kScratchRegister, type);
return; return;
} }
// Move rhs into rcx. If rcx is in use, move its content into the scratch // Move amount into rcx. If rcx is in use, move its content into the scratch
// register. If lhs is rcx, lhs is now the scratch register. // register. If src is rcx, src is now the scratch register.
bool use_scratch = false; bool use_scratch = false;
if (rhs != rcx) { if (amount != rcx) {
use_scratch = lhs == rcx || use_scratch = src == rcx ||
assm->cache_state()->is_used(LiftoffRegister(rcx)) || assm->cache_state()->is_used(LiftoffRegister(rcx)) ||
pinned.has(LiftoffRegister(rcx)); pinned.has(LiftoffRegister(rcx));
if (use_scratch) assm->movq(kScratchRegister, rcx); if (use_scratch) assm->movq(kScratchRegister, rcx);
if (lhs == rcx) lhs = kScratchRegister; if (src == rcx) src = kScratchRegister;
assm->movl(rcx, rhs); assm->Move(rcx, amount, type);
} }
// Do the actual shift. // Do the actual shift.
if (dst != lhs) assm->movl(dst, lhs); if (dst != src) assm->Move(dst, src, type);
(assm->*emit_shift)(dst); (assm->*emit_shift)(dst);
// Restore rcx if needed. // Restore rcx if needed.
...@@ -437,19 +438,22 @@ inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst, ...@@ -437,19 +438,22 @@ inline void EmitShiftOperation(LiftoffAssembler* assm, Register dst,
} }
} // namespace liftoff } // 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) { 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) { 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) { 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) { bool LiftoffAssembler::emit_i32_clz(Register dst, Register src) {
...@@ -493,6 +497,24 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { ...@@ -493,6 +497,24 @@ bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
return true; 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, void LiftoffAssembler::emit_ptrsize_add(Register dst, Register lhs,
Register rhs) { Register rhs) {
if (lhs != dst) { if (lhs != dst) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment