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

[Liftoff] Implement f32.min and f32.max

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

R=ahaas@chromium.org

Bug: v8:6600
Change-Id: If73abf3cf46011ba84158ed2ec02d074adcf4ba2
Reviewed-on: https://chromium-review.googlesource.com/1027841
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52803}
parent 5e3e7ad3
......@@ -168,6 +168,8 @@ UNIMPLEMENTED_FP_BINOP(f32_add)
UNIMPLEMENTED_FP_BINOP(f32_sub)
UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
......
......@@ -301,6 +301,8 @@ UNIMPLEMENTED_FP_BINOP(f32_add)
UNIMPLEMENTED_FP_BINOP(f32_sub)
UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
......
......@@ -919,6 +919,67 @@ 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) {
Label is_nan;
Label lhs_below_rhs;
Label lhs_above_rhs;
Label done;
// We need one tmp register to extract the sign bit. Get it right at the
// beginning, such that the spilling code is not accidentially jumped over.
Register tmp = assm->GetUnusedRegister(kGpReg).gp();
// 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);
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
// If we get here, then either
// a) {lhs == rhs},
// b) {lhs == -0.0} and {rhs == 0.0}, or
// 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);
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);
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);
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);
assm->bind(&done);
}
} // namespace liftoff
void LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitF32MinOrMax(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);
}
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint32_t kSignBit = uint32_t{1} << 31;
if (dst == src) {
......
......@@ -459,6 +459,11 @@ class LiftoffAssembler : public TurboAssembler {
DoubleRegister rhs);
inline void emit_f32_div(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
inline void emit_f32_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
inline void emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
// f32 unops.
inline void emit_f32_abs(DoubleRegister dst, DoubleRegister src);
inline void emit_f32_neg(DoubleRegister dst, DoubleRegister src);
......
......@@ -901,6 +901,8 @@ class LiftoffCompiler {
CASE_FLOAT_BINOP(F32Sub, F32, f32_sub)
CASE_FLOAT_BINOP(F32Mul, F32, f32_mul)
CASE_FLOAT_BINOP(F32Div, F32, f32_div)
CASE_FLOAT_BINOP(F32Min, F32, f32_min)
CASE_FLOAT_BINOP(F32Max, F32, f32_max)
CASE_FLOAT_BINOP(F64Add, F64, f64_add)
CASE_FLOAT_BINOP(F64Sub, F64, f64_sub)
CASE_FLOAT_BINOP(F64Mul, F64, f64_mul)
......
......@@ -759,6 +759,8 @@ FP_BINOP(f32_add, add_s)
FP_BINOP(f32_sub, sub_s)
FP_BINOP(f32_mul, mul_s)
FP_BINOP(f32_div, div_s)
FP_BINOP(f32_min, min_s)
FP_BINOP(f32_max, max_s)
FP_UNOP(f32_abs, abs_s)
FP_UNOP(f32_ceil, Ceil_s_s)
FP_UNOP(f32_floor, Floor_s_s)
......
......@@ -632,6 +632,8 @@ FP_BINOP(f32_add, add_s)
FP_BINOP(f32_sub, sub_s)
FP_BINOP(f32_mul, mul_s)
FP_BINOP(f32_div, div_s)
FP_BINOP(f32_min, min_s)
FP_BINOP(f32_max, max_s)
FP_UNOP(f32_abs, abs_s)
FP_UNOP(f32_ceil, Ceil_s_s)
FP_UNOP(f32_floor, Floor_s_s)
......
......@@ -173,6 +173,8 @@ UNIMPLEMENTED_FP_BINOP(f32_add)
UNIMPLEMENTED_FP_BINOP(f32_sub)
UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
......
......@@ -173,6 +173,8 @@ UNIMPLEMENTED_FP_BINOP(f32_add)
UNIMPLEMENTED_FP_BINOP(f32_sub)
UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
......
......@@ -816,6 +816,63 @@ 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) {
Label is_nan;
Label lhs_below_rhs;
Label lhs_above_rhs;
Label done;
// 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);
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
// If we get here, then either
// a) {lhs == rhs},
// b) {lhs == -0.0} and {rhs == 0.0}, or
// 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);
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);
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);
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);
assm->bind(&done);
}
} // namespace liftoff
void LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitF32MinOrMax(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);
}
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint32_t kSignBit = uint32_t{1} << 31;
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