[turbofan] Introduce optional Float64Min and Float64Max machine operators.

Basically recognize certain x < y ? x : y constructs and turn that into
Float64Min/Float64Max operations, if the target machine supports that.
On x86 we lower to (v)minsd/(v)maxsd.

R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/998283002

Cr-Commit-Position: refs/heads/master@{#27160}
This commit is contained in:
bmeurer 2015-03-12 07:07:28 -07:00 committed by Commit bot
parent 1aae3a1c89
commit 99f8d57f3c
30 changed files with 480 additions and 33 deletions

View File

@ -1000,6 +1000,12 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
}
void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmVsqrtF64, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));

View File

@ -1069,6 +1069,12 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
}
void InstructionSelector::VisitFloat64Max(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat64Min(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
VisitRRFloat64(this, kArm64Float64Sqrt, node);
}

View File

@ -4,8 +4,12 @@
#include "src/compiler/common-operator-reducer.h"
#include <algorithm>
#include "src/compiler/common-operator.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node.h"
#include "src/compiler/node-matchers.h"
namespace v8 {
namespace internal {
@ -14,29 +18,119 @@ namespace compiler {
Reduction CommonOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kEffectPhi:
case IrOpcode::kPhi: {
int const input_count = node->InputCount();
if (input_count > 1) {
Node* const replacement = node->InputAt(0);
for (int i = 1; i < input_count - 1; ++i) {
if (node->InputAt(i) != replacement) return NoChange();
}
return Replace(replacement);
}
break;
}
case IrOpcode::kSelect: {
if (node->InputAt(1) == node->InputAt(2)) {
return Replace(node->InputAt(1));
}
break;
}
return ReduceEffectPhi(node);
case IrOpcode::kPhi:
return ReducePhi(node);
case IrOpcode::kSelect:
return ReduceSelect(node);
default:
break;
}
return NoChange();
}
Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
int const input_count = node->InputCount();
if (input_count > 1) {
Node* const replacement = node->InputAt(0);
for (int i = 1; i < input_count - 1; ++i) {
if (node->InputAt(i) != replacement) return NoChange();
}
return Replace(replacement);
}
return NoChange();
}
Reduction CommonOperatorReducer::ReducePhi(Node* node) {
DCHECK_EQ(IrOpcode::kPhi, node->opcode());
int const input_count = node->InputCount();
if (input_count == 3) {
Node* vtrue = NodeProperties::GetValueInput(node, 0);
Node* vfalse = NodeProperties::GetValueInput(node, 1);
Node* merge = NodeProperties::GetControlInput(node);
Node* if_true = NodeProperties::GetControlInput(merge, 0);
Node* if_false = NodeProperties::GetControlInput(merge, 1);
if (if_true->opcode() != IrOpcode::kIfTrue) {
std::swap(if_true, if_false);
std::swap(vtrue, vfalse);
}
if (if_true->opcode() == IrOpcode::kIfTrue &&
if_false->opcode() == IrOpcode::kIfFalse &&
if_true->InputAt(0) == if_false->InputAt(0)) {
Node* branch = if_true->InputAt(0);
Node* cond = branch->InputAt(0);
if (cond->opcode() == IrOpcode::kFloat64LessThan) {
if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
machine()->HasFloat64Min()) {
node->set_op(machine()->Float64Min());
node->ReplaceInput(0, vtrue);
node->ReplaceInput(1, vfalse);
node->TrimInputCount(2);
return Changed(node);
} else if (cond->InputAt(0) == vfalse && cond->InputAt(1) == vtrue &&
machine()->HasFloat64Max()) {
node->set_op(machine()->Float64Max());
node->ReplaceInput(0, vtrue);
node->ReplaceInput(1, vfalse);
node->TrimInputCount(2);
return Changed(node);
}
}
}
}
if (input_count > 1) {
Node* const replacement = node->InputAt(0);
for (int i = 1; i < input_count - 1; ++i) {
if (node->InputAt(i) != replacement) return NoChange();
}
return Replace(replacement);
}
return NoChange();
}
Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
DCHECK_EQ(IrOpcode::kSelect, node->opcode());
Node* cond = NodeProperties::GetValueInput(node, 0);
Node* vtrue = NodeProperties::GetValueInput(node, 1);
Node* vfalse = NodeProperties::GetValueInput(node, 2);
if (vtrue == vfalse) return Replace(vtrue);
if (cond->opcode() == IrOpcode::kFloat64LessThan) {
if (cond->InputAt(0) == vtrue && cond->InputAt(1) == vfalse &&
machine()->HasFloat64Min()) {
node->set_op(machine()->Float64Min());
node->ReplaceInput(0, vtrue);
node->ReplaceInput(1, vfalse);
node->TrimInputCount(2);
return Changed(node);
} else if (cond->InputAt(0) == vfalse && cond->InputAt(1) == vtrue &&
machine()->HasFloat64Max()) {
node->set_op(machine()->Float64Max());
node->ReplaceInput(0, vtrue);
node->ReplaceInput(1, vfalse);
node->TrimInputCount(2);
return Changed(node);
}
}
return NoChange();
}
CommonOperatorBuilder* CommonOperatorReducer::common() const {
return jsgraph()->common();
}
Graph* CommonOperatorReducer::graph() const { return jsgraph()->graph(); }
MachineOperatorBuilder* CommonOperatorReducer::machine() const {
return jsgraph()->machine();
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -11,13 +11,32 @@ namespace v8 {
namespace internal {
namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
class Graph;
class JSGraph;
class MachineOperatorBuilder;
// Performs strength reduction on nodes that have common operators.
class CommonOperatorReducer FINAL : public Reducer {
public:
CommonOperatorReducer() {}
explicit CommonOperatorReducer(JSGraph* jsgraph) : jsgraph_(jsgraph) {}
~CommonOperatorReducer() FINAL {}
Reduction Reduce(Node* node) FINAL;
private:
Reduction ReduceEffectPhi(Node* node);
Reduction ReducePhi(Node* node);
Reduction ReduceSelect(Node* node);
CommonOperatorBuilder* common() const;
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
MachineOperatorBuilder* machine() const;
JSGraph* const jsgraph_;
};
} // namespace compiler

View File

@ -462,6 +462,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kSSEFloat64Div:
__ divsd(i.InputDoubleRegister(0), i.InputOperand(1));
break;
case kSSEFloat64Max:
__ maxsd(i.InputDoubleRegister(0), i.InputOperand(1));
break;
case kSSEFloat64Min:
__ minsd(i.InputDoubleRegister(0), i.InputOperand(1));
break;
case kSSEFloat64Mod: {
// TODO(dcarney): alignment is wrong.
__ sub(esp, Immediate(kDoubleSize));
@ -567,6 +573,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
i.InputOperand(1));
break;
}
case kAVXFloat64Max: {
CpuFeatureScope avx_scope(masm(), AVX);
__ vmaxsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
i.InputOperand(1));
break;
}
case kAVXFloat64Min: {
CpuFeatureScope avx_scope(masm(), AVX);
__ vminsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
i.InputOperand(1));
break;
}
case kIA32Movsxbl:
__ movsx_b(i.OutputRegister(), i.MemoryOperand());
break;

View File

@ -36,6 +36,8 @@ namespace compiler {
V(SSEFloat64Mul) \
V(SSEFloat64Div) \
V(SSEFloat64Mod) \
V(SSEFloat64Max) \
V(SSEFloat64Min) \
V(SSEFloat64Sqrt) \
V(SSEFloat64Round) \
V(SSECvtss2sd) \
@ -53,6 +55,8 @@ namespace compiler {
V(AVXFloat64Sub) \
V(AVXFloat64Mul) \
V(AVXFloat64Div) \
V(AVXFloat64Max) \
V(AVXFloat64Min) \
V(IA32Movsxbl) \
V(IA32Movzxbl) \
V(IA32Movb) \

View File

@ -702,6 +702,30 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
}
void InstructionSelector::VisitFloat64Max(Node* node) {
IA32OperandGenerator g(this);
if (IsSupported(AVX)) {
Emit(kAVXFloat64Max, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
} else {
Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
}
}
void InstructionSelector::VisitFloat64Min(Node* node) {
IA32OperandGenerator g(this);
if (IsSupported(AVX)) {
Emit(kAVXFloat64Min, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
} else {
Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
}
}
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
IA32OperandGenerator g(this);
Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@ -1135,6 +1159,8 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::Flags flags =
MachineOperatorBuilder::kFloat64Max |
MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kWord32ShiftIsSafe;
if (CpuFeatures::IsSupported(SSE4_1)) {
flags |= MachineOperatorBuilder::kFloat64RoundDown |

View File

@ -689,6 +689,8 @@ MachineType InstructionSelector::GetMachineType(Node* node) {
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
case IrOpcode::kFloat64Max:
case IrOpcode::kFloat64Min:
case IrOpcode::kFloat64Sqrt:
case IrOpcode::kFloat64RoundDown:
case IrOpcode::kFloat64RoundTruncate:
@ -892,6 +894,10 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsDouble(node), VisitFloat64Div(node);
case IrOpcode::kFloat64Mod:
return MarkAsDouble(node), VisitFloat64Mod(node);
case IrOpcode::kFloat64Min:
return MarkAsDouble(node), VisitFloat64Min(node);
case IrOpcode::kFloat64Max:
return MarkAsDouble(node), VisitFloat64Max(node);
case IrOpcode::kFloat64Sqrt:
return MarkAsDouble(node), VisitFloat64Sqrt(node);
case IrOpcode::kFloat64Equal:

View File

@ -133,6 +133,8 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1) \
V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \
V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \
V(Float64Max, Operator::kNoProperties, 2, 0, 1) \
V(Float64Min, Operator::kNoProperties, 2, 0, 1) \
V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1)

View File

@ -74,12 +74,14 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
// for operations that are unsupported by some back-ends.
enum Flag {
kNoFlags = 0u,
kFloat64RoundDown = 1u << 0,
kFloat64RoundTruncate = 1u << 1,
kFloat64RoundTiesAway = 1u << 2,
kInt32DivIsSafe = 1u << 3,
kUint32DivIsSafe = 1u << 4,
kWord32ShiftIsSafe = 1u << 5
kFloat64Max = 1u << 0,
kFloat64Min = 1u << 1,
kFloat64RoundDown = 1u << 2,
kFloat64RoundTruncate = 1u << 3,
kFloat64RoundTiesAway = 1u << 4,
kInt32DivIsSafe = 1u << 5,
kUint32DivIsSafe = 1u << 6,
kWord32ShiftIsSafe = 1u << 7
};
typedef base::Flags<Flag, unsigned> Flags;
@ -166,6 +168,12 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Float64LessThan();
const Operator* Float64LessThanOrEqual();
// Floating point min/max complying to IEEE 754.
const Operator* Float64Max();
const Operator* Float64Min();
bool HasFloat64Max() { return flags_ & kFloat64Max; }
bool HasFloat64Min() { return flags_ & kFloat64Min; }
// Floating point rounding.
const Operator* Float64RoundDown();
const Operator* Float64RoundTruncate();

View File

@ -248,6 +248,8 @@
V(Float64Mul) \
V(Float64Div) \
V(Float64Mod) \
V(Float64Max) \
V(Float64Min) \
V(Float64Sqrt) \
V(Float64RoundDown) \
V(Float64RoundTruncate) \

View File

@ -494,7 +494,7 @@ struct TypedLoweringPhase {
JSTypedLowering typed_lowering(data->jsgraph(), temp_zone);
JSIntrinsicLowering intrinsic_lowering(data->jsgraph());
SimplifiedOperatorReducer simple_reducer(data->jsgraph());
CommonOperatorReducer common_reducer;
CommonOperatorReducer common_reducer(data->jsgraph());
GraphReducer graph_reducer(data->graph(), temp_zone);
AddReducer(data, &graph_reducer, &vn_reducer);
AddReducer(data, &graph_reducer, &builtin_reducer);
@ -520,7 +520,7 @@ struct SimplifiedLoweringPhase {
ValueNumberingReducer vn_reducer(temp_zone);
SimplifiedOperatorReducer simple_reducer(data->jsgraph());
MachineOperatorReducer machine_reducer(data->jsgraph());
CommonOperatorReducer common_reducer;
CommonOperatorReducer common_reducer(data->jsgraph());
GraphReducer graph_reducer(data->graph(), temp_zone);
AddReducer(data, &graph_reducer, &vn_reducer);
AddReducer(data, &graph_reducer, &simple_reducer);
@ -553,7 +553,7 @@ struct ChangeLoweringPhase {
SimplifiedOperatorReducer simple_reducer(data->jsgraph());
ChangeLowering lowering(data->jsgraph());
MachineOperatorReducer machine_reducer(data->jsgraph());
CommonOperatorReducer common_reducer;
CommonOperatorReducer common_reducer(data->jsgraph());
GraphReducer graph_reducer(data->graph(), temp_zone);
AddReducer(data, &graph_reducer, &vn_reducer);
AddReducer(data, &graph_reducer, &simple_reducer);

View File

@ -1028,6 +1028,7 @@ class RepresentationSelector {
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
case IrOpcode::kFloat64Min:
return VisitFloat64Binop(node);
case IrOpcode::kFloat64Sqrt:
case IrOpcode::kFloat64RoundDown:

View File

@ -2066,6 +2066,16 @@ Bounds Typer::Visitor::TypeFloat64Mod(Node* node) {
}
Bounds Typer::Visitor::TypeFloat64Max(Node* node) {
return Bounds(Type::Number());
}
Bounds Typer::Visitor::TypeFloat64Min(Node* node) {
return Bounds(Type::Number());
}
Bounds Typer::Visitor::TypeFloat64Sqrt(Node* node) {
return Bounds(Type::Number());
}

View File

@ -792,6 +792,8 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kFloat64Mul:
case IrOpcode::kFloat64Div:
case IrOpcode::kFloat64Mod:
case IrOpcode::kFloat64Max:
case IrOpcode::kFloat64Min:
case IrOpcode::kFloat64Sqrt:
case IrOpcode::kFloat64RoundDown:
case IrOpcode::kFloat64RoundTruncate:

View File

@ -741,6 +741,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ addq(rsp, Immediate(kDoubleSize));
break;
}
case kSSEFloat64Max:
ASSEMBLE_DOUBLE_BINOP(maxsd);
break;
case kSSEFloat64Min:
ASSEMBLE_DOUBLE_BINOP(minsd);
break;
case kSSEFloat64Sqrt:
if (instr->InputAt(0)->IsDoubleRegister()) {
__ sqrtsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
@ -847,6 +853,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kAVXFloat64Div:
ASSEMBLE_AVX_DOUBLE_BINOP(vdivsd);
break;
case kAVXFloat64Max:
ASSEMBLE_AVX_DOUBLE_BINOP(vmaxsd);
break;
case kAVXFloat64Min:
ASSEMBLE_AVX_DOUBLE_BINOP(vminsd);
break;
case kX64Movsxbl:
ASSEMBLE_MOVX(movsxbl);
__ AssertZeroExtended(i.OutputRegister());

View File

@ -54,6 +54,8 @@ namespace compiler {
V(SSEFloat64Mod) \
V(SSEFloat64Sqrt) \
V(SSEFloat64Round) \
V(SSEFloat64Max) \
V(SSEFloat64Min) \
V(SSECvtss2sd) \
V(SSECvtsd2ss) \
V(SSEFloat64ToInt32) \
@ -69,6 +71,8 @@ namespace compiler {
V(AVXFloat64Sub) \
V(AVXFloat64Mul) \
V(AVXFloat64Div) \
V(AVXFloat64Max) \
V(AVXFloat64Min) \
V(X64Movsxbl) \
V(X64Movzxbl) \
V(X64Movb) \

View File

@ -900,6 +900,30 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
}
void InstructionSelector::VisitFloat64Max(Node* node) {
X64OperandGenerator g(this);
if (IsSupported(AVX)) {
Emit(kAVXFloat64Max, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
} else {
Emit(kSSEFloat64Max, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
}
}
void InstructionSelector::VisitFloat64Min(Node* node) {
X64OperandGenerator g(this);
if (IsSupported(AVX)) {
Emit(kAVXFloat64Min, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
} else {
Emit(kSSEFloat64Min, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), g.Use(node->InputAt(1)));
}
}
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
X64OperandGenerator g(this);
Emit(kSSEFloat64Sqrt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@ -1449,6 +1473,8 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) {
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::Flags flags =
MachineOperatorBuilder::kFloat64Max |
MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kWord32ShiftIsSafe;
if (CpuFeatures::IsSupported(SSE4_1)) {
flags |= MachineOperatorBuilder::kFloat64RoundDown |

View File

@ -2235,6 +2235,24 @@ void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
}
void Assembler::maxsd(XMMRegister dst, const Operand& src) {
EnsureSpace ensure_space(this);
EMIT(0xF2);
EMIT(0x0F);
EMIT(0x5F);
emit_sse_operand(dst, src);
}
void Assembler::minsd(XMMRegister dst, const Operand& src) {
EnsureSpace ensure_space(this);
EMIT(0xF2);
EMIT(0x0F);
EMIT(0x5D);
emit_sse_operand(dst, src);
}
void Assembler::cmpltsd(XMMRegister dst, XMMRegister src) {
EnsureSpace ensure_space(this);
EMIT(0xF2);

View File

@ -1022,6 +1022,11 @@ class Assembler : public AssemblerBase {
void punpckldq(XMMRegister dst, XMMRegister src);
void punpckhdq(XMMRegister dst, XMMRegister src);
void maxsd(XMMRegister dst, XMMRegister src) { maxsd(dst, Operand(src)); }
void maxsd(XMMRegister dst, const Operand& src);
void minsd(XMMRegister dst, XMMRegister src) { minsd(dst, Operand(src)); }
void minsd(XMMRegister dst, const Operand& src);
void movdqa(XMMRegister dst, const Operand& src);
void movdqa(const Operand& dst, XMMRegister src);
void movdqu(XMMRegister dst, const Operand& src);
@ -1246,6 +1251,18 @@ class Assembler : public AssemblerBase {
void vdivsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x5e, dst, src1, src2);
}
void vmaxsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
vmaxsd(dst, src1, Operand(src2));
}
void vmaxsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x5f, dst, src1, src2);
}
void vminsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
vminsd(dst, src1, Operand(src2));
}
void vminsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x5d, dst, src1, src2);
}
void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);
// Prefetch src position into cache level.

View File

@ -826,11 +826,21 @@ int DisassemblerIA32::AVXInstruction(byte* data) {
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0x5d:
AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0x5e:
AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0x5f:
AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
default:
UnimplementedInstruction();
}
@ -1758,7 +1768,13 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
case 0x58: mnem = "addsd"; break;
case 0x59: mnem = "mulsd"; break;
case 0x5C: mnem = "subsd"; break;
case 0x5D:
mnem = "minsd";
break;
case 0x5E: mnem = "divsd"; break;
case 0x5F:
mnem = "maxsd";
break;
}
data += 3;
int mod, regop, rm;

View File

@ -3314,6 +3314,46 @@ void Assembler::punpckhdq(XMMRegister dst, XMMRegister src) {
}
void Assembler::maxsd(XMMRegister dst, XMMRegister src) {
EnsureSpace ensure_space(this);
emit(0xF2);
emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0x5F);
emit_sse_operand(dst, src);
}
void Assembler::maxsd(XMMRegister dst, const Operand& src) {
EnsureSpace ensure_space(this);
emit(0xF2);
emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0x5F);
emit_sse_operand(dst, src);
}
void Assembler::minsd(XMMRegister dst, XMMRegister src) {
EnsureSpace ensure_space(this);
emit(0xF2);
emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0x5D);
emit_sse_operand(dst, src);
}
void Assembler::minsd(XMMRegister dst, const Operand& src) {
EnsureSpace ensure_space(this);
emit(0xF2);
emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0x5D);
emit_sse_operand(dst, src);
}
// AVX instructions
void Assembler::vfmasd(byte op, XMMRegister dst, XMMRegister src1,
XMMRegister src2) {

View File

@ -1144,6 +1144,11 @@ class Assembler : public AssemblerBase {
void punpckldq(XMMRegister dst, XMMRegister src);
void punpckhdq(XMMRegister dst, XMMRegister src);
void maxsd(XMMRegister dst, XMMRegister src);
void maxsd(XMMRegister dst, const Operand& src);
void minsd(XMMRegister dst, XMMRegister src);
void minsd(XMMRegister dst, const Operand& src);
// SSE 4.1 instruction
void extractps(Register dst, XMMRegister src, byte imm8);
@ -1329,6 +1334,18 @@ class Assembler : public AssemblerBase {
void vdivsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x5e, dst, src1, src2);
}
void vmaxsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
vsd(0x5f, dst, src1, src2);
}
void vmaxsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x5f, dst, src1, src2);
}
void vminsd(XMMRegister dst, XMMRegister src1, XMMRegister src2) {
vsd(0x5d, dst, src1, src2);
}
void vminsd(XMMRegister dst, XMMRegister src1, const Operand& src2) {
vsd(0x5d, dst, src1, src2);
}
void vsd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2);
void vsd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2);

View File

@ -956,11 +956,21 @@ int DisassemblerX64::AVXInstruction(byte* data) {
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0x5d:
AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0x5e:
AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
case 0x5f:
AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
NameOfXMMRegister(vvvv));
current += PrintRightXMMOperand(current);
break;
default:
UnimplementedInstruction();
}
@ -1543,10 +1553,14 @@ const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
return "mulsd";
case 0x5A: // F2 prefix.
return "cvtsd2ss";
case 0x5D: // F2 prefix.
return "minsd";
case 0x5C: // F2 prefix.
return "subsd";
case 0x5E: // F2 prefix.
return "divsd";
case 0x5F: // F2 prefix.
return "maxsd";
case 0xA2:
return "cpuid";
case 0xA5:

View File

@ -442,6 +442,10 @@ TEST(DisasmIa320) {
__ subsd(xmm1, Operand(ebx, ecx, times_4, 10000));
__ divsd(xmm1, xmm0);
__ divsd(xmm1, Operand(ebx, ecx, times_4, 10000));
__ minsd(xmm1, xmm0);
__ minsd(xmm1, Operand(ebx, ecx, times_4, 10000));
__ maxsd(xmm1, xmm0);
__ maxsd(xmm1, Operand(ebx, ecx, times_4, 10000));
__ ucomisd(xmm0, xmm1);
__ cmpltsd(xmm0, xmm1);
@ -499,6 +503,10 @@ TEST(DisasmIa320) {
__ vsubsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
__ vdivsd(xmm0, xmm1, xmm2);
__ vdivsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
__ vminsd(xmm0, xmm1, xmm2);
__ vminsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
__ vmaxsd(xmm0, xmm1, xmm2);
__ vmaxsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
}
}

View File

@ -436,6 +436,10 @@ TEST(DisasmX64) {
__ subsd(xmm1, Operand(rbx, rcx, times_4, 10000));
__ divsd(xmm1, xmm0);
__ divsd(xmm1, Operand(rbx, rcx, times_4, 10000));
__ minsd(xmm1, xmm0);
__ minsd(xmm1, Operand(rbx, rcx, times_4, 10000));
__ maxsd(xmm1, xmm0);
__ maxsd(xmm1, Operand(rbx, rcx, times_4, 10000));
__ ucomisd(xmm0, xmm1);
__ andpd(xmm0, xmm1);
@ -493,7 +497,11 @@ TEST(DisasmX64) {
__ vsubsd(xmm0, xmm1, xmm2);
__ vsubsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
__ vdivsd(xmm0, xmm1, xmm2);
__ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
__ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_2, 10000));
__ vminsd(xmm8, xmm1, xmm2);
__ vminsd(xmm9, xmm1, Operand(rbx, rcx, times_8, 10000));
__ vmaxsd(xmm8, xmm1, xmm2);
__ vmaxsd(xmm9, xmm1, Operand(rbx, rcx, times_1, 10000));
}
}

View File

@ -4,9 +4,13 @@
#include "src/compiler/common-operator.h"
#include "src/compiler/common-operator-reducer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/machine-type.h"
#include "src/compiler/operator.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
namespace v8 {
namespace internal {
@ -15,14 +19,23 @@ namespace compiler {
class CommonOperatorReducerTest : public GraphTest {
public:
explicit CommonOperatorReducerTest(int num_parameters = 1)
: GraphTest(num_parameters) {}
: GraphTest(num_parameters), machine_(zone()) {}
~CommonOperatorReducerTest() OVERRIDE {}
protected:
Reduction Reduce(Node* node) {
CommonOperatorReducer reducer;
Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
MachineOperatorBuilder::kNoFlags) {
JSOperatorBuilder javascript(zone());
MachineOperatorBuilder machine(zone(), kMachPtr, flags);
JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
CommonOperatorReducer reducer(&jsgraph);
return reducer.Reduce(node);
}
MachineOperatorBuilder* machine() { return &machine_; }
private:
MachineOperatorBuilder machine_;
};
@ -77,10 +90,15 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) {
TRACED_FORRANGE(int, input_count, 2, kMaxInputs - 1) {
int const value_input_count = input_count - 1;
TRACED_FOREACH(MachineType, type, kMachineTypes) {
for (int i = 0; i < value_input_count; ++i) {
inputs[i] = graph()->start();
}
Node* merge = graph()->NewNode(common()->Merge(value_input_count),
value_input_count, inputs);
for (int i = 0; i < value_input_count; ++i) {
inputs[i] = input;
}
inputs[value_input_count] = graph()->start();
inputs[value_input_count] = merge;
Reduction r = Reduce(graph()->NewNode(
common()->Phi(type, value_input_count), input_count, inputs));
ASSERT_TRUE(r.Changed());
@ -90,6 +108,27 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) {
}
TEST_F(CommonOperatorReducerTest, PhiToFloat64MaxOrFloat64Min) {
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start());
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Reduction r1 =
Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p1, p0, merge),
MachineOperatorBuilder::kFloat64Max);
ASSERT_TRUE(r1.Changed());
EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0));
Reduction r2 =
Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge),
MachineOperatorBuilder::kFloat64Min);
ASSERT_TRUE(r2.Changed());
EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1));
}
// -----------------------------------------------------------------------------
// Select
@ -106,6 +145,23 @@ TEST_F(CommonOperatorReducerTest, RedundantSelect) {
}
}
TEST_F(CommonOperatorReducerTest, SelectToFloat64MaxOrFloat64Min) {
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1);
Reduction r1 =
Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p1, p0),
MachineOperatorBuilder::kFloat64Max);
ASSERT_TRUE(r1.Changed());
EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0));
Reduction r2 =
Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p0, p1),
MachineOperatorBuilder::kFloat64Min);
ASSERT_TRUE(r2.Changed());
EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1));
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -209,7 +209,8 @@ const PureOperator kPureOperators[] = {
PURE(Float64RoundTiesAway, 1, 0, 1), PURE(Float64ExtractLowWord32, 1, 0, 1),
PURE(Float64ExtractHighWord32, 1, 0, 1),
PURE(Float64InsertLowWord32, 2, 0, 1),
PURE(Float64InsertHighWord32, 2, 0, 1)
PURE(Float64InsertHighWord32, 2, 0, 1), PURE(Float64Max, 2, 0, 1),
PURE(Float64Min, 2, 0, 1)
#undef PURE
};

View File

@ -1590,6 +1590,8 @@ IS_BINOP_MATCHER(Int32MulHigh)
IS_BINOP_MATCHER(Int32LessThan)
IS_BINOP_MATCHER(Uint32LessThan)
IS_BINOP_MATCHER(Uint32LessThanOrEqual)
IS_BINOP_MATCHER(Float64Max)
IS_BINOP_MATCHER(Float64Min)
IS_BINOP_MATCHER(Float64Sub)
IS_BINOP_MATCHER(Float64InsertLowWord32)
IS_BINOP_MATCHER(Float64InsertHighWord32)

View File

@ -203,6 +203,10 @@ Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsTruncateFloat64ToFloat32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsFloat64Max(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsFloat64Min(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsFloat64Sub(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher);