Commit 43216574 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce NumberFloor simplified operator.

The NumberFloor operator matches exactly the semantics of the Math.floor
builtin on Numbers. It uses hardware rounding instructions if available,
but provides a full fallback solution that is compatible with Math.floor.
The lowering is optimizable based on types if needed later, i.e. we
already optimize it for the case that the input is already an Integer
(in the EcmaScript sense, including NaN and -0), but we could add more
optimizations, like combining NumberFloor and NumberDivide in the
future, if necessary.

R=jarin@chromium.org
BUG=v8:2890,v8:4059
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#35090}
parent 7b342a23
...@@ -132,11 +132,9 @@ Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { ...@@ -132,11 +132,9 @@ Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
// ES6 draft 08-24-14, section 20.2.2.16. // ES6 draft 08-24-14, section 20.2.2.16.
Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) { Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number()) && if (r.InputsMatchOne(Type::Number())) {
machine()->Float64RoundDown().IsSupported()) { // Math.floor(a:number) -> NumberFloor(a)
// Math.floor(a:number) -> Float64RoundDown(a) Node* value = graph()->NewNode(simplified()->NumberFloor(), r.left());
Node* value =
graph()->NewNode(machine()->Float64RoundDown().op(), r.left());
return Replace(value); return Replace(value);
} }
return NoChange(); return NoChange();
......
...@@ -183,6 +183,7 @@ ...@@ -183,6 +183,7 @@
V(NumberShiftLeft) \ V(NumberShiftLeft) \
V(NumberShiftRight) \ V(NumberShiftRight) \
V(NumberShiftRightLogical) \ V(NumberShiftRightLogical) \
V(NumberFloor) \
V(NumberToInt32) \ V(NumberToInt32) \
V(NumberToUint32) \ V(NumberToUint32) \
V(NumberIsHoleNaN) \ V(NumberIsHoleNaN) \
......
...@@ -649,6 +649,7 @@ struct TypedLoweringPhase { ...@@ -649,6 +649,7 @@ struct TypedLoweringPhase {
data->info()->is_deoptimization_enabled() data->info()->is_deoptimization_enabled()
? JSIntrinsicLowering::kDeoptimizationEnabled ? JSIntrinsicLowering::kDeoptimizationEnabled
: JSIntrinsicLowering::kDeoptimizationDisabled); : JSIntrinsicLowering::kDeoptimizationDisabled);
SimplifiedOperatorReducer simple_reducer(data->jsgraph());
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(), CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
data->common(), data->machine()); data->common(), data->machine());
AddReducer(data, &graph_reducer, &dead_code_elimination); AddReducer(data, &graph_reducer, &dead_code_elimination);
...@@ -659,6 +660,7 @@ struct TypedLoweringPhase { ...@@ -659,6 +660,7 @@ struct TypedLoweringPhase {
AddReducer(data, &graph_reducer, &typed_lowering); AddReducer(data, &graph_reducer, &typed_lowering);
AddReducer(data, &graph_reducer, &intrinsic_lowering); AddReducer(data, &graph_reducer, &intrinsic_lowering);
AddReducer(data, &graph_reducer, &load_elimination); AddReducer(data, &graph_reducer, &load_elimination);
AddReducer(data, &graph_reducer, &simple_reducer);
AddReducer(data, &graph_reducer, &common_reducer); AddReducer(data, &graph_reducer, &common_reducer);
graph_reducer.ReduceGraph(); graph_reducer.ReduceGraph();
} }
......
...@@ -962,6 +962,11 @@ class RepresentationSelector { ...@@ -962,6 +962,11 @@ class RepresentationSelector {
} }
break; break;
} }
case IrOpcode::kNumberFloor: {
VisitUnop(node, UseInfo::Float64(), MachineRepresentation::kFloat64);
if (lower()) DeferReplacement(node, lowering->Float64Floor(node));
break;
}
case IrOpcode::kNumberToInt32: { case IrOpcode::kNumberToInt32: {
// Just change representation if necessary. // Just change representation if necessary.
VisitUnop(node, UseInfo::TruncatingWord32(), VisitUnop(node, UseInfo::TruncatingWord32(),
...@@ -1519,6 +1524,132 @@ void SimplifiedLowering::DoStoreBuffer(Node* node) { ...@@ -1519,6 +1524,132 @@ void SimplifiedLowering::DoStoreBuffer(Node* node) {
NodeProperties::ChangeOp(node, machine()->CheckedStore(rep)); NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
} }
Node* SimplifiedLowering::Float64Floor(Node* const node) {
Node* const one = jsgraph()->Float64Constant(1.0);
Node* const zero = jsgraph()->Float64Constant(0.0);
Node* const minus_one = jsgraph()->Float64Constant(-1.0);
Node* const minus_zero = jsgraph()->Float64Constant(-0.0);
Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0);
Node* const minus_two_52 = jsgraph()->Float64Constant(-4503599627370496.0E0);
Node* const input = node->InputAt(0);
// Use fast hardware instruction if available.
if (machine()->Float64RoundDown().IsSupported()) {
return graph()->NewNode(machine()->Float64RoundDown().op(), input);
}
// General case for floor.
//
// if 0.0 < input then
// if 2^52 <= input then
// input
// else
// let temp1 = (2^52 + input) - 2^52 in
// if input < temp1 then
// temp1 - 1
// else
// temp1
// else
// if input == 0 then
// input
// else
// if input <= -2^52 then
// input
// else
// let temp1 = -0 - input in
// let temp2 = (2^52 + temp1) - 2^52 in
// if temp2 < temp1 then
// -1 - temp2
// else
// -0 - temp2
//
// Note: We do not use the Diamond helper class here, because it really hurts
// readability with nested diamonds.
Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input);
Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
graph()->start());
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* vtrue0;
{
Node* check1 =
graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input);
Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* vtrue1 = input;
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* vfalse1;
{
Node* temp1 = graph()->NewNode(
machine()->Float64Sub(),
graph()->NewNode(machine()->Float64Add(), two_52, input), two_52);
vfalse1 = graph()->NewNode(
common()->Select(MachineRepresentation::kFloat64),
graph()->NewNode(machine()->Float64LessThan(), input, temp1),
graph()->NewNode(machine()->Float64Sub(), temp1, one), temp1);
}
if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
vtrue1, vfalse1, if_true0);
}
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* vfalse0;
{
Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero);
Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check1, if_false0);
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
Node* vtrue1 = input;
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
Node* vfalse1;
{
Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(),
input, minus_two_52);
Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
check2, if_false1);
Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
Node* vtrue2 = input;
Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
Node* vfalse2;
{
Node* temp1 =
graph()->NewNode(machine()->Float64Sub(), minus_zero, input);
Node* temp2 = graph()->NewNode(
machine()->Float64Sub(),
graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52);
vfalse2 = graph()->NewNode(
common()->Select(MachineRepresentation::kFloat64),
graph()->NewNode(machine()->Float64LessThan(), temp2, temp1),
graph()->NewNode(machine()->Float64Sub(), minus_one, temp2),
graph()->NewNode(machine()->Float64Sub(), minus_zero, temp2));
}
if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
vfalse1 =
graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
vtrue2, vfalse2, if_false1);
}
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
vfalse0 =
graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
vtrue1, vfalse1, if_false0);
}
Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
return graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
vtrue0, vfalse0, merge0);
}
Node* SimplifiedLowering::Int32Div(Node* const node) { Node* SimplifiedLowering::Int32Div(Node* const node) {
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
Node* const zero = jsgraph()->Int32Constant(0); Node* const zero = jsgraph()->Int32Constant(0);
......
...@@ -55,6 +55,7 @@ class SimplifiedLowering final { ...@@ -55,6 +55,7 @@ class SimplifiedLowering final {
// position information via the SourcePositionWrapper like all other reducers. // position information via the SourcePositionWrapper like all other reducers.
SourcePositionTable* source_positions_; SourcePositionTable* source_positions_;
Node* Float64Floor(Node* const node);
Node* Int32Div(Node* const node); Node* Int32Div(Node* const node);
Node* Int32Mod(Node* const node); Node* Int32Mod(Node* const node);
Node* Uint32Div(Node* const node); Node* Uint32Div(Node* const node);
......
...@@ -9,14 +9,14 @@ ...@@ -9,14 +9,14 @@
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/operator-properties.h" #include "src/compiler/operator-properties.h"
#include "src/conversions-inl.h" #include "src/conversions-inl.h"
#include "src/type-cache.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
SimplifiedOperatorReducer::SimplifiedOperatorReducer(JSGraph* jsgraph) SimplifiedOperatorReducer::SimplifiedOperatorReducer(JSGraph* jsgraph)
: jsgraph_(jsgraph) {} : jsgraph_(jsgraph), type_cache_(TypeCache::Get()) {}
SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {} SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {}
...@@ -89,6 +89,8 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) { ...@@ -89,6 +89,8 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
if (m.HasValue()) return ReplaceNumber(FastUI2D(m.Value())); if (m.HasValue()) return ReplaceNumber(FastUI2D(m.Value()));
break; break;
} }
case IrOpcode::kNumberFloor:
return ReduceNumberFloor(node);
case IrOpcode::kReferenceEqual: case IrOpcode::kReferenceEqual:
return ReduceReferenceEqual(node); return ReduceReferenceEqual(node);
default: default:
...@@ -97,6 +99,15 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) { ...@@ -97,6 +99,15 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
return NoChange(); return NoChange();
} }
Reduction SimplifiedOperatorReducer::ReduceNumberFloor(Node* node) {
DCHECK_EQ(IrOpcode::kNumberFloor, node->opcode());
Node* const input = NodeProperties::GetValueInput(node, 0);
Type* const input_type = NodeProperties::GetType(input);
if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
return Replace(input);
}
return NoChange();
}
Reduction SimplifiedOperatorReducer::ReduceReferenceEqual(Node* node) { Reduction SimplifiedOperatorReducer::ReduceReferenceEqual(Node* node) {
DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode()); DCHECK_EQ(IrOpcode::kReferenceEqual, node->opcode());
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Forward declarations.
class TypeCache;
namespace compiler { namespace compiler {
// Forward declarations. // Forward declarations.
...@@ -25,6 +29,7 @@ class SimplifiedOperatorReducer final : public Reducer { ...@@ -25,6 +29,7 @@ class SimplifiedOperatorReducer final : public Reducer {
Reduction Reduce(Node* node) final; Reduction Reduce(Node* node) final;
private: private:
Reduction ReduceNumberFloor(Node* node);
Reduction ReduceReferenceEqual(Node* node); Reduction ReduceReferenceEqual(Node* node);
Reduction Change(Node* node, const Operator* op, Node* a); Reduction Change(Node* node, const Operator* op, Node* a);
...@@ -42,6 +47,7 @@ class SimplifiedOperatorReducer final : public Reducer { ...@@ -42,6 +47,7 @@ class SimplifiedOperatorReducer final : public Reducer {
SimplifiedOperatorBuilder* simplified() const; SimplifiedOperatorBuilder* simplified() const;
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
TypeCache const& type_cache_;
DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorReducer); DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorReducer);
}; };
......
...@@ -173,6 +173,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) { ...@@ -173,6 +173,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
V(NumberShiftLeft, Operator::kNoProperties, 2) \ V(NumberShiftLeft, Operator::kNoProperties, 2) \
V(NumberShiftRight, Operator::kNoProperties, 2) \ V(NumberShiftRight, Operator::kNoProperties, 2) \
V(NumberShiftRightLogical, Operator::kNoProperties, 2) \ V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
V(NumberFloor, Operator::kNoProperties, 1) \
V(NumberToInt32, Operator::kNoProperties, 1) \ V(NumberToInt32, Operator::kNoProperties, 1) \
V(NumberToUint32, Operator::kNoProperties, 1) \ V(NumberToUint32, Operator::kNoProperties, 1) \
V(NumberIsHoleNaN, Operator::kNoProperties, 1) \ V(NumberIsHoleNaN, Operator::kNoProperties, 1) \
......
...@@ -143,6 +143,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject { ...@@ -143,6 +143,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberShiftLeft(); const Operator* NumberShiftLeft();
const Operator* NumberShiftRight(); const Operator* NumberShiftRight();
const Operator* NumberShiftRightLogical(); const Operator* NumberShiftRightLogical();
const Operator* NumberFloor();
const Operator* NumberToInt32(); const Operator* NumberToInt32();
const Operator* NumberToUint32(); const Operator* NumberToUint32();
const Operator* NumberIsHoleNaN(); const Operator* NumberIsHoleNaN();
......
...@@ -240,6 +240,7 @@ class Typer::Visitor : public Reducer { ...@@ -240,6 +240,7 @@ class Typer::Visitor : public Reducer {
static Type* ToNumber(Type*, Typer*); static Type* ToNumber(Type*, Typer*);
static Type* ToObject(Type*, Typer*); static Type* ToObject(Type*, Typer*);
static Type* ToString(Type*, Typer*); static Type* ToString(Type*, Typer*);
static Type* NumberFloor(Type*, Typer*);
static Type* NumberToInt32(Type*, Typer*); static Type* NumberToInt32(Type*, Typer*);
static Type* NumberToUint32(Type*, Typer*); static Type* NumberToUint32(Type*, Typer*);
...@@ -487,6 +488,12 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) { ...@@ -487,6 +488,12 @@ Type* Typer::Visitor::ToString(Type* type, Typer* t) {
return Type::String(); return Type::String();
} }
// static
Type* Typer::Visitor::NumberFloor(Type* type, Typer* t) {
DCHECK(type->Is(Type::Number()));
if (type->Is(t->cache_.kIntegerOrMinusZeroOrNaN)) return type;
return t->cache_.kIntegerOrMinusZeroOrNaN;
}
Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) { Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
// TODO(neis): DCHECK(type->Is(Type::Number())); // TODO(neis): DCHECK(type->Is(Type::Number()));
...@@ -1715,6 +1722,9 @@ Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) { ...@@ -1715,6 +1722,9 @@ Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) {
return Type::Unsigned32(); return Type::Unsigned32();
} }
Type* Typer::Visitor::TypeNumberFloor(Node* node) {
return TypeUnaryOp(node, NumberFloor);
}
Type* Typer::Visitor::TypeNumberToInt32(Node* node) { Type* Typer::Visitor::TypeNumberToInt32(Node* node) {
return TypeUnaryOp(node, NumberToInt32); return TypeUnaryOp(node, NumberToInt32);
......
...@@ -677,6 +677,11 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -677,6 +677,11 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Unsigned32()); CheckValueInputIs(node, 1, Type::Unsigned32());
CheckUpperIs(node, Type::Unsigned32()); CheckUpperIs(node, Type::Unsigned32());
break; break;
case IrOpcode::kNumberFloor:
// Number -> Number
CheckValueInputIs(node, 0, Type::Number());
CheckUpperIs(node, Type::Number());
break;
case IrOpcode::kNumberToInt32: case IrOpcode::kNumberToInt32:
// Number -> Signed32 // Number -> Signed32
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
......
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