Commit a4ce8e3e authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[liftoff][x64] Use cmov for the select opcode

cmov is often much faster than branches (in particular if the branches
cannot be predicted). It also has a much more predictable performance,
and is shorter.
This CL uses cmov on x64 for now. Other platforms (maybe using other
instructions than cmov) can be added later.

R=thibaudm@chromium.org

Bug: v8:10740
Change-Id: Ifab3d570b8eea784376e1f768d6ba3828efcc01a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2315978Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69027}
parent 8403d5f1
...@@ -2177,6 +2177,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -2177,6 +2177,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
} }
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadType type,
......
...@@ -1436,6 +1436,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -1436,6 +1436,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
} }
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadType type,
......
...@@ -2332,6 +2332,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -2332,6 +2332,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
liftoff::EmitFloatSetCond<&Assembler::ucomisd>(this, cond, dst, lhs, rhs); liftoff::EmitFloatSetCond<&Assembler::ucomisd>(this, cond, dst, lhs, rhs);
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
namespace liftoff { namespace liftoff {
template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister), template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister),
void (Assembler::*sse_op)(XMMRegister, XMMRegister)> void (Assembler::*sse_op)(XMMRegister, XMMRegister)>
......
...@@ -745,6 +745,12 @@ class LiftoffAssembler : public TurboAssembler { ...@@ -745,6 +745,12 @@ class LiftoffAssembler : public TurboAssembler {
inline void emit_f64_set_cond(Condition condition, Register dst, inline void emit_f64_set_cond(Condition condition, Register dst,
DoubleRegister lhs, DoubleRegister rhs); DoubleRegister lhs, DoubleRegister rhs);
// Optional select support: Returns false if generic code (via branches)
// should be emitted instead.
inline bool emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value, ValueType type);
inline void LoadTransform(LiftoffRegister dst, Register src_addr, inline void LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadTransformationKind transform, LoadType type, LoadTransformationKind transform,
......
...@@ -1801,10 +1801,8 @@ class LiftoffCompiler { ...@@ -1801,10 +1801,8 @@ class LiftoffCompiler {
LiftoffRegister true_value = __ PopToRegister(pinned); LiftoffRegister true_value = __ PopToRegister(pinned);
LiftoffRegister dst = __ GetUnusedRegister(true_value.reg_class(), LiftoffRegister dst = __ GetUnusedRegister(true_value.reg_class(),
{true_value, false_value}, {}); {true_value, false_value}, {});
__ PushRegister(type, dst); if (!__ emit_select(dst, condition, true_value, false_value, type)) {
// Emit generic code (using branches) instead.
// Now emit the actual code to move either {true_value} or {false_value}
// into {dst}.
Label cont; Label cont;
Label case_false; Label case_false;
__ emit_cond_jump(kEqual, &case_false, kWasmI32, condition); __ emit_cond_jump(kEqual, &case_false, kWasmI32, condition);
...@@ -1815,6 +1813,8 @@ class LiftoffCompiler { ...@@ -1815,6 +1813,8 @@ class LiftoffCompiler {
if (dst != false_value) __ Move(dst, false_value, type); if (dst != false_value) __ Move(dst, false_value, type);
__ bind(&cont); __ bind(&cont);
} }
__ PushRegister(type, dst);
}
void BrImpl(Control* target) { void BrImpl(Control* target) {
if (!target->br_merge()->reached) { if (!target->br_merge()->reached) {
......
...@@ -1569,6 +1569,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -1569,6 +1569,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
bind(&cont); bind(&cont);
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadType type,
......
...@@ -1404,6 +1404,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -1404,6 +1404,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
bind(&cont); bind(&cont);
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadType type,
......
...@@ -549,6 +549,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -549,6 +549,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
bailout(kUnsupportedArchitecture, "emit_f64_set_cond"); bailout(kUnsupportedArchitecture, "emit_f64_set_cond");
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadType type,
......
...@@ -553,6 +553,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -553,6 +553,13 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
bailout(kUnsupportedArchitecture, "emit_f64_set_cond"); bailout(kUnsupportedArchitecture, "emit_f64_set_cond");
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
return false;
}
void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
Register offset_reg, uint32_t offset_imm, Register offset_reg, uint32_t offset_imm,
LoadType type, LoadType type,
......
...@@ -2040,6 +2040,33 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst, ...@@ -2040,6 +2040,33 @@ void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
rhs); rhs);
} }
bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
LiftoffRegister true_value,
LiftoffRegister false_value,
ValueType type) {
if (type != kWasmI32 && type != kWasmI64) return false;
testl(condition, condition);
if (type == kWasmI32) {
if (dst == false_value) {
cmovl(not_zero, dst.gp(), true_value.gp());
} else {
if (dst != true_value) movl(dst.gp(), true_value.gp());
cmovl(zero, dst.gp(), false_value.gp());
}
} else {
if (dst == false_value) {
cmovq(not_zero, dst.gp(), true_value.gp());
} else {
if (dst != true_value) movq(dst.gp(), true_value.gp());
cmovq(zero, dst.gp(), false_value.gp());
}
}
return true;
}
// TODO(fanchenk): Distinguish mov* if data bypass delay matter. // TODO(fanchenk): Distinguish mov* if data bypass delay matter.
namespace liftoff { namespace liftoff {
template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister), template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister),
......
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