Index: src/compiler/js-builtin-reducer.cc |
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc |
index 17ce5785f191001c7c2e830dd9cb4d389b97bbdb..83161e14a5d5388582c23fa9a4617725a371aaa6 100644 |
--- a/src/compiler/js-builtin-reducer.cc |
+++ b/src/compiler/js-builtin-reducer.cc |
@@ -48,23 +48,35 @@ class JSCallReduction { |
return function->shared()->builtin_function_id(); |
} |
+ // Determines whether the call takes zero inputs. |
+ bool InputsMatchZero() { return GetJSCallArity() == 0; } |
+ |
// Determines whether the call takes one input of the given type. |
- bool InputsMatch(Type* t1) { |
+ bool InputsMatchOne(Type* t1) { |
return GetJSCallArity() == 1 && |
NodeProperties::GetBounds(GetJSCallInput(0)).upper->Is(t1); |
} |
// Determines whether the call takes two inputs of the given types. |
- bool InputsMatch(Type* t1, Type* t2) { |
+ bool InputsMatchTwo(Type* t1, Type* t2) { |
return GetJSCallArity() == 2 && |
NodeProperties::GetBounds(GetJSCallInput(0)).upper->Is(t1) && |
NodeProperties::GetBounds(GetJSCallInput(1)).upper->Is(t2); |
} |
+ // Determines whether the call takes inputs all of the given type. |
+ bool InputsMatchAll(Type* t) { |
+ for (int i = 0; i < GetJSCallArity(); i++) { |
+ if (!NodeProperties::GetBounds(GetJSCallInput(i)).upper->Is(t)) { |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
Node* left() { return GetJSCallInput(0); } |
Node* right() { return GetJSCallInput(1); } |
- protected: |
int GetJSCallArity() { |
DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); |
// Skip first (i.e. callee) and second (i.e. receiver) operand. |
@@ -83,10 +95,42 @@ class JSCallReduction { |
}; |
+// ECMA-262, section 15.8.2.11. |
+Reduction JSBuiltinReducer::ReduceMathMax(Node* node) { |
+ JSCallReduction r(node); |
+ if (r.InputsMatchZero()) { |
+ // Math.max() -> -Infinity |
+ return Replace(jsgraph()->Constant(-V8_INFINITY)); |
+ } |
+ if (r.InputsMatchOne(Type::Number())) { |
+ // Math.max(a:number) -> a |
+ return Replace(r.left()); |
+ } |
+ if (r.InputsMatchAll(Type::Integral32())) { |
+ // Math.max(a:int32, b:int32, ...) |
+ Node* value = r.GetJSCallInput(0); |
+ for (int i = 1; i < r.GetJSCallArity(); i++) { |
+ Node* p = r.GetJSCallInput(i); |
+ Node* control = graph()->start(); |
+ Node* tag = graph()->NewNode(simplified()->NumberLessThan(), value, p); |
+ |
+ Node* branch = graph()->NewNode(common()->Branch(), tag, control); |
+ 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); |
+ |
+ value = graph()->NewNode(common()->Phi(kMachNone, 2), p, value, merge); |
+ } |
+ return Replace(value); |
+ } |
+ return NoChange(); |
+} |
+ |
+ |
// ES6 draft 08-24-14, section 20.2.2.19. |
Reduction JSBuiltinReducer::ReduceMathImul(Node* node) { |
JSCallReduction r(node); |
- if (r.InputsMatch(Type::Integral32(), Type::Integral32())) { |
+ if (r.InputsMatchTwo(Type::Integral32(), Type::Integral32())) { |
// Math.imul(a:int32, b:int32) -> Int32Mul(a, b) |
Node* value = graph()->NewNode(machine()->Int32Mul(), r.left(), r.right()); |
return Replace(value); |
@@ -101,6 +145,8 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { |
// Dispatch according to the BuiltinFunctionId if present. |
if (!r.HasBuiltinFunctionId()) return NoChange(); |
switch (r.GetBuiltinFunctionId()) { |
+ case kMathMax: |
+ return ReplaceWithPureReduction(node, ReduceMathMax(node)); |
case kMathImul: |
return ReplaceWithPureReduction(node, ReduceMathImul(node)); |
default: |