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

[Liftoff] Implement float to i64/u64 conversions

This implement float to i64/u64 conversions on ia32 and x64.
These conversions emit a C call on ia32, and are implemented using
native instructions on x64.

R=ahaas@chromium.org

Bug: v8:6600
Change-Id: I5b97a74d336e196598b29d407a3d06405b74ee14
Reviewed-on: https://chromium-review.googlesource.com/1014114
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52705}
parent 93df7ff0
......@@ -45,12 +45,17 @@ static_assert(kByteRegs.GetNumRegsSet() == 4, "should have four byte regs");
static_assert((kByteRegs & kGpCacheRegList) == kByteRegs,
"kByteRegs only contains gp cache registers");
inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Operand src,
ValueType type) {
inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base,
int32_t offset, ValueType type) {
Operand src(base, offset);
switch (type) {
case kWasmI32:
assm->mov(dst.gp(), src);
break;
case kWasmI64:
assm->mov(dst.low_gp(), src);
assm->mov(dst.high_gp(), Operand(base, offset + 4));
break;
case kWasmF32:
assm->movss(dst.fp(), src);
break;
......@@ -329,8 +334,7 @@ void LiftoffAssembler::ChangeEndiannessStore(LiftoffRegister src,
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
uint32_t caller_slot_idx,
ValueType type) {
Operand src(ebp, kPointerSize * (caller_slot_idx + 1));
liftoff::Load(this, dst, src, type);
liftoff::Load(this, dst, ebp, kPointerSize * (caller_slot_idx + 1), type);
}
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
......@@ -1371,7 +1375,7 @@ void LiftoffAssembler::CallC(wasm::FunctionSig* sig,
// Load potential output value from the buffer on the stack.
if (out_argument_type != kWasmStmt) {
liftoff::Load(this, *next_result_reg, Operand(esp, 0), out_argument_type);
liftoff::Load(this, *next_result_reg, esp, 0, out_argument_type);
}
add(esp, Immediate(stack_bytes));
......
......@@ -624,9 +624,10 @@ class LiftoffCompiler {
static constexpr RegClass dst_rc = reg_class_for(dst_type);
LiftoffRegList pinned;
LiftoffRegister src = pinned.set(__ PopToRegister());
LiftoffRegister dst = src_rc == dst_rc
? __ GetUnusedRegister(dst_rc, {src}, pinned)
: __ GetUnusedRegister(dst_rc, pinned);
LiftoffRegister dst = pinned.set(
src_rc == dst_rc ? __ GetUnusedRegister(dst_rc, {src}, pinned)
: __ GetUnusedRegister(dst_rc, pinned));
DCHECK_EQ(can_trap, trap_position > 0);
Label* trap = can_trap ? AddOutOfLineTrap(
trap_position,
Builtins::kThrowWasmTrapFloatUnrepresentable)
......@@ -634,9 +635,19 @@ class LiftoffCompiler {
if (!__ emit_type_conversion(opcode, dst, src, trap)) {
DCHECK_NOT_NULL(fallback_fn);
ExternalReference ext_ref = fallback_fn(asm_->isolate());
ValueType sig_reps[] = {src_type};
FunctionSig sig(0, 1, sig_reps);
GenerateCCall(&dst, &sig, dst_type, &src, ext_ref);
if (can_trap) {
// External references for potentially trapping conversions return int.
ValueType sig_reps[] = {kWasmI32, src_type};
FunctionSig sig(1, 1, sig_reps);
LiftoffRegister ret_reg = __ GetUnusedRegister(kGpReg, pinned);
LiftoffRegister dst_regs[] = {ret_reg, dst};
GenerateCCall(dst_regs, &sig, dst_type, &src, ext_ref);
__ emit_cond_jump(kEqual, trap, kWasmI32, ret_reg.gp());
} else {
ValueType sig_reps[] = {src_type};
FunctionSig sig(0, 1, sig_reps);
GenerateCCall(&dst, &sig, dst_type, &src, ext_ref);
}
}
__ PushRegister(dst_type, dst);
}
......@@ -688,6 +699,14 @@ class LiftoffCompiler {
CASE_TYPE_CONVERSION(I32ReinterpretF32, I32, F32, nullptr, kNoTrap)
CASE_TYPE_CONVERSION(I64SConvertI32, I64, I32, nullptr, kNoTrap)
CASE_TYPE_CONVERSION(I64UConvertI32, I64, I32, nullptr, kNoTrap)
CASE_TYPE_CONVERSION(I64SConvertF32, I64, F32,
&ExternalReference::wasm_float32_to_int64, kCanTrap)
CASE_TYPE_CONVERSION(I64UConvertF32, I64, F32,
&ExternalReference::wasm_float32_to_uint64, kCanTrap)
CASE_TYPE_CONVERSION(I64SConvertF64, I64, F64,
&ExternalReference::wasm_float64_to_int64, kCanTrap)
CASE_TYPE_CONVERSION(I64UConvertF64, I64, F64,
&ExternalReference::wasm_float64_to_uint64, kCanTrap)
CASE_TYPE_CONVERSION(I64ReinterpretF64, I64, F64, nullptr, kNoTrap)
CASE_TYPE_CONVERSION(F32SConvertI32, F32, I32, nullptr, kNoTrap)
CASE_TYPE_CONVERSION(F32UConvertI32, F32, I32, nullptr, kNoTrap)
......
......@@ -14,8 +14,11 @@ namespace v8 {
namespace internal {
namespace wasm {
#define REQUIRE_CPU_FEATURE(name) \
if (!CpuFeatures::IsSupported(name)) return bailout("no " #name); \
#define REQUIRE_CPU_FEATURE(name, ...) \
if (!CpuFeatures::IsSupported(name)) { \
bailout("no " #name); \
return __VA_ARGS__; \
} \
CpuFeatureScope feature(this, name);
namespace liftoff {
......@@ -819,22 +822,32 @@ inline void ConvertFloatToIntAndBack(LiftoffAssembler* assm, Register dst,
DoubleRegister src,
DoubleRegister converted_back) {
if (std::is_same<double, src_type>::value) { // f64
if (std::is_signed<dst_type>::value) { // f64 -> i32
if (std::is_same<int32_t, dst_type>::value) { // f64 -> i32
assm->Cvttsd2si(dst, src);
assm->Cvtlsi2sd(converted_back, dst);
} else { // f64 -> u32
} else if (std::is_same<uint32_t, dst_type>::value) { // f64 -> u32
assm->Cvttsd2siq(dst, src);
assm->movl(dst, dst);
assm->Cvtqsi2sd(converted_back, dst);
} else if (std::is_same<int64_t, dst_type>::value) { // f64 -> i64
assm->Cvttsd2siq(dst, src);
assm->Cvtqsi2sd(converted_back, dst);
} else {
UNREACHABLE();
}
} else { // f32
if (std::is_signed<dst_type>::value) { // f32 -> i32
if (std::is_same<int32_t, dst_type>::value) { // f32 -> i32
assm->Cvttss2si(dst, src);
assm->Cvtlsi2ss(converted_back, dst);
} else { // f32 -> u32
} else if (std::is_same<uint32_t, dst_type>::value) { // f32 -> u32
assm->Cvttss2siq(dst, src);
assm->movl(dst, dst);
assm->Cvtqsi2ss(converted_back, dst);
} else if (std::is_same<int64_t, dst_type>::value) { // f32 -> i64
assm->Cvttss2siq(dst, src);
assm->Cvtqsi2ss(converted_back, dst);
} else {
UNREACHABLE();
}
}
}
......@@ -899,6 +912,22 @@ bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
case kExprI64SConvertI32:
movsxlq(dst.gp(), src.gp());
return true;
case kExprI64SConvertF32:
return liftoff::EmitTruncateFloatToInt<int64_t, float>(this, dst.gp(),
src.fp(), trap);
case kExprI64UConvertF32: {
REQUIRE_CPU_FEATURE(SSE4_1, true);
Cvttss2uiq(dst.gp(), src.fp(), trap);
return true;
}
case kExprI64SConvertF64:
return liftoff::EmitTruncateFloatToInt<int64_t, double>(this, dst.gp(),
src.fp(), trap);
case kExprI64UConvertF64: {
REQUIRE_CPU_FEATURE(SSE4_1, true);
Cvttsd2uiq(dst.gp(), src.fp(), trap);
return true;
}
case kExprI64UConvertI32:
AssertZeroExtended(src.gp());
if (dst.gp() != src.gp()) movl(dst.gp(), src.gp());
......
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