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

[Liftoff] Implement f64.min and f64.max

This adds support for f64.min and f64.max, implemented on ia32, x64,
mips and mips64.

R=ahaas@chromium.org

Bug: v8:6600
Change-Id: Ib4383df08692c76df5861fe71a96c4354fdf10c1
Reviewed-on: https://chromium-review.googlesource.com/1028235
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52838}
parent 649c2526
......@@ -181,6 +181,8 @@ UNIMPLEMENTED_FP_BINOP(f64_add)
UNIMPLEMENTED_FP_BINOP(f64_sub)
UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP(f64_ceil)
......
......@@ -314,6 +314,8 @@ UNIMPLEMENTED_FP_BINOP(f64_add)
UNIMPLEMENTED_FP_BINOP(f64_sub)
UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP(f64_ceil)
......
......@@ -921,9 +921,10 @@ void LiftoffAssembler::emit_f32_div(DoubleRegister dst, DoubleRegister lhs,
namespace liftoff {
enum class MinOrMax : uint8_t { kMin, kMax };
inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
DoubleRegister lhs, DoubleRegister rhs,
MinOrMax min_or_max) {
template <typename type>
inline void EmitFloatMinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
DoubleRegister lhs, DoubleRegister rhs,
MinOrMax min_or_max) {
Label is_nan;
Label lhs_below_rhs;
Label lhs_above_rhs;
......@@ -933,9 +934,18 @@ inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
// beginning, such that the spilling code is not accidentially jumped over.
Register tmp = assm->GetUnusedRegister(kGpReg).gp();
#define dop(name, ...) \
do { \
if (sizeof(type) == 4) { \
assm->name##s(__VA_ARGS__); \
} else { \
assm->name##d(__VA_ARGS__); \
} \
} while (false)
// Check the easy cases first: nan (e.g. unordered), smaller and greater.
// NaN has to be checked first, because PF=1 implies CF=1.
assm->ucomiss(lhs, rhs);
dop(ucomis, lhs, rhs);
assm->j(parity_even, &is_nan, Label::kNear); // PF=1
assm->j(below, &lhs_below_rhs, Label::kNear); // CF=1
assm->j(above, &lhs_above_rhs, Label::kNear); // CF=0 && ZF=0
......@@ -946,25 +956,25 @@ inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
// c) {lhs == 0.0} and {rhs == -0.0}.
// For a), it does not matter whether we return {lhs} or {rhs}. Check the sign
// bit of {rhs} to differentiate b) and c).
assm->movmskps(tmp, rhs);
dop(movmskp, tmp, rhs);
assm->test(tmp, Immediate(1));
assm->j(zero, &lhs_below_rhs, Label::kNear);
assm->jmp(&lhs_above_rhs, Label::kNear);
assm->bind(&is_nan);
// Create a NaN output.
assm->xorps(dst, dst);
assm->divss(dst, dst);
dop(xorp, dst, dst);
dop(divs, dst, dst);
assm->jmp(&done, Label::kNear);
assm->bind(&lhs_below_rhs);
DoubleRegister lhs_below_rhs_src = min_or_max == MinOrMax::kMin ? lhs : rhs;
if (dst != lhs_below_rhs_src) assm->movss(dst, lhs_below_rhs_src);
if (dst != lhs_below_rhs_src) dop(movs, dst, lhs_below_rhs_src);
assm->jmp(&done, Label::kNear);
assm->bind(&lhs_above_rhs);
DoubleRegister lhs_above_rhs_src = min_or_max == MinOrMax::kMin ? rhs : lhs;
if (dst != lhs_above_rhs_src) assm->movss(dst, lhs_above_rhs_src);
if (dst != lhs_above_rhs_src) dop(movs, dst, lhs_above_rhs_src);
assm->bind(&done);
}
......@@ -972,12 +982,14 @@ inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
void LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitF32MinOrMax(this, dst, lhs, rhs, liftoff::MinOrMax::kMin);
liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMin);
}
void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitF32MinOrMax(this, dst, lhs, rhs, liftoff::MinOrMax::kMax);
liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMax);
}
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
......@@ -1083,6 +1095,18 @@ void LiftoffAssembler::emit_f64_div(DoubleRegister dst, DoubleRegister lhs,
}
}
void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMin);
}
void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMax);
}
void LiftoffAssembler::emit_f64_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint64_t kSignBit = uint64_t{1} << 63;
if (dst == src) {
......
......@@ -482,6 +482,10 @@ class LiftoffAssembler : public TurboAssembler {
DoubleRegister rhs);
inline void emit_f64_div(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
inline void emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
inline void emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
// f64 unops.
inline void emit_f64_abs(DoubleRegister dst, DoubleRegister src);
......
......@@ -907,6 +907,8 @@ class LiftoffCompiler {
CASE_FLOAT_BINOP(F64Sub, F64, f64_sub)
CASE_FLOAT_BINOP(F64Mul, F64, f64_mul)
CASE_FLOAT_BINOP(F64Div, F64, f64_div)
CASE_FLOAT_BINOP(F64Min, F64, f64_min)
CASE_FLOAT_BINOP(F64Max, F64, f64_max)
case WasmOpcode::kExprI32DivS:
EmitBinOp<kWasmI32, kWasmI32>([this, decoder](LiftoffRegister dst,
LiftoffRegister lhs,
......
......@@ -767,6 +767,28 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
bind(&done);
}
void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
Label ool, done;
TurboAssembler::Float64Min(dst, lhs, rhs, &ool);
Branch(&done);
bind(&ool);
TurboAssembler::Float64MinOutOfLine(dst, lhs, rhs);
bind(&done);
}
void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
Label ool, done;
TurboAssembler::Float64Max(dst, lhs, rhs, &ool);
Branch(&done);
bind(&ool);
TurboAssembler::Float64MaxOutOfLine(dst, lhs, rhs);
bind(&done);
}
#define FP_BINOP(name, instruction) \
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
DoubleRegister rhs) { \
......
......@@ -640,6 +640,28 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
bind(&done);
}
void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
Label ool, done;
TurboAssembler::Float64Min(dst, lhs, rhs, &ool);
Branch(&done);
bind(&ool);
TurboAssembler::Float64MinOutOfLine(dst, lhs, rhs);
bind(&done);
}
void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
Label ool, done;
TurboAssembler::Float64Max(dst, lhs, rhs, &ool);
Branch(&done);
bind(&ool);
TurboAssembler::Float64MaxOutOfLine(dst, lhs, rhs);
bind(&done);
}
#define FP_BINOP(name, instruction) \
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
DoubleRegister rhs) { \
......
......@@ -186,6 +186,8 @@ UNIMPLEMENTED_FP_BINOP(f64_add)
UNIMPLEMENTED_FP_BINOP(f64_sub)
UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP(f64_ceil)
......
......@@ -186,6 +186,8 @@ UNIMPLEMENTED_FP_BINOP(f64_add)
UNIMPLEMENTED_FP_BINOP(f64_sub)
UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP(f64_ceil)
......
......@@ -818,17 +818,27 @@ void LiftoffAssembler::emit_f32_div(DoubleRegister dst, DoubleRegister lhs,
namespace liftoff {
enum class MinOrMax : uint8_t { kMin, kMax };
inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
DoubleRegister lhs, DoubleRegister rhs,
MinOrMax min_or_max) {
template <typename type>
inline void EmitFloatMinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
DoubleRegister lhs, DoubleRegister rhs,
MinOrMax min_or_max) {
Label is_nan;
Label lhs_below_rhs;
Label lhs_above_rhs;
Label done;
#define dop(name, ...) \
do { \
if (sizeof(type) == 4) { \
assm->name##s(__VA_ARGS__); \
} else { \
assm->name##d(__VA_ARGS__); \
} \
} while (false)
// Check the easy cases first: nan (e.g. unordered), smaller and greater.
// NaN has to be checked first, because PF=1 implies CF=1.
assm->Ucomiss(lhs, rhs);
dop(Ucomis, lhs, rhs);
assm->j(parity_even, &is_nan, Label::kNear); // PF=1
assm->j(below, &lhs_below_rhs, Label::kNear); // CF=1
assm->j(above, &lhs_above_rhs, Label::kNear); // CF=0 && ZF=0
......@@ -839,25 +849,25 @@ inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
// c) {lhs == 0.0} and {rhs == -0.0}.
// For a), it does not matter whether we return {lhs} or {rhs}. Check the sign
// bit of {rhs} to differentiate b) and c).
assm->Movmskps(kScratchRegister, rhs);
dop(Movmskp, kScratchRegister, rhs);
assm->testl(kScratchRegister, Immediate(1));
assm->j(zero, &lhs_below_rhs, Label::kNear);
assm->jmp(&lhs_above_rhs, Label::kNear);
assm->bind(&is_nan);
// Create a NaN output.
assm->Xorps(dst, dst);
assm->Divss(dst, dst);
dop(Xorp, dst, dst);
dop(Divs, dst, dst);
assm->jmp(&done, Label::kNear);
assm->bind(&lhs_below_rhs);
DoubleRegister lhs_below_rhs_src = min_or_max == MinOrMax::kMin ? lhs : rhs;
if (dst != lhs_below_rhs_src) assm->Movss(dst, lhs_below_rhs_src);
if (dst != lhs_below_rhs_src) dop(Movs, dst, lhs_below_rhs_src);
assm->jmp(&done, Label::kNear);
assm->bind(&lhs_above_rhs);
DoubleRegister lhs_above_rhs_src = min_or_max == MinOrMax::kMin ? rhs : lhs;
if (dst != lhs_above_rhs_src) assm->Movss(dst, lhs_above_rhs_src);
if (dst != lhs_above_rhs_src) dop(Movs, dst, lhs_above_rhs_src);
assm->bind(&done);
}
......@@ -865,12 +875,14 @@ inline void EmitF32MinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
void LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitF32MinOrMax(this, dst, lhs, rhs, liftoff::MinOrMax::kMin);
liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMin);
}
void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitF32MinOrMax(this, dst, lhs, rhs, liftoff::MinOrMax::kMax);
liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMax);
}
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
......@@ -976,6 +988,18 @@ void LiftoffAssembler::emit_f64_div(DoubleRegister dst, DoubleRegister lhs,
}
}
void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMin);
}
void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,
liftoff::MinOrMax::kMax);
}
void LiftoffAssembler::emit_f64_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint64_t kSignBit = uint64_t{1} << 63;
if (dst == src) {
......
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