Add JSBuiltinReducer for inlining well-known builtins.

R=titzer@chromium.org
TEST=cctest/test-js-typed-lowering/BuiltinMathImul

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24095 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 40bbeef0
......@@ -504,6 +504,8 @@ source_set("v8_base") {
"src/compiler/instruction-selector.h",
"src/compiler/instruction.cc",
"src/compiler/instruction.h",
"src/compiler/js-builtin-reducer.cc",
"src/compiler/js-builtin-reducer.h",
"src/compiler/js-context-specialization.cc",
"src/compiler/js-context-specialization.h",
"src/compiler/js-generic-lowering.cc",
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/graph-inl.h"
#include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties-inl.h"
#include "src/types.h"
namespace v8 {
namespace internal {
namespace compiler {
// Helper method that assumes replacement nodes are pure values that don't
// produce an effect. Replaces {node} with {reduction} and relaxes effects.
static Reduction ReplaceWithPureReduction(Node* node, Reduction reduction) {
if (reduction.Changed()) {
NodeProperties::ReplaceWithValue(node, reduction.replacement());
return reduction;
}
return Reducer::NoChange();
}
// Helper class to access JSCallFunction nodes that are potential candidates
// for reduction when they have a BuiltinFunctionId associated with them.
class JSCallReduction {
public:
explicit JSCallReduction(Node* node) : node_(node) {}
// Determines whether the node is a JSCallFunction operation that targets a
// constant callee being a well-known builtin with a BuiltinFunctionId.
bool HasBuiltinFunctionId() {
if (node_->opcode() != IrOpcode::kJSCallFunction) return false;
HeapObjectMatcher<JSFunction> m(NodeProperties::GetValueInput(node_, 0));
return m.HasValue() && m.Value().handle()->shared()->HasBuiltinFunctionId();
}
// Retrieves the BuiltinFunctionId as described above.
BuiltinFunctionId GetBuiltinFunctionId() {
DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
HeapObjectMatcher<JSFunction> m(NodeProperties::GetValueInput(node_, 0));
return m.Value().handle()->shared()->builtin_function_id();
}
// Determines whether the call takes one input of the given type.
bool InputsMatch(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) {
return GetJSCallArity() == 2 &&
NodeProperties::GetBounds(GetJSCallInput(0)).upper->Is(t1) &&
NodeProperties::GetBounds(GetJSCallInput(1)).upper->Is(t2);
}
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.
return OperatorProperties::GetValueInputCount(node_->op()) - 2;
}
Node* GetJSCallInput(int index) {
DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
DCHECK_LT(index, GetJSCallArity());
// Skip first (i.e. callee) and second (i.e. receiver) operand.
return NodeProperties::GetValueInput(node_, index + 2);
}
private:
Node* node_;
};
// 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())) {
// Math.imul(a:int32, b:int32) -> Int32Mul(a, b)
Node* value = graph()->NewNode(machine()->Int32Mul(), r.left(), r.right());
return Replace(value);
}
return NoChange();
}
Reduction JSBuiltinReducer::Reduce(Node* node) {
JSCallReduction r(node);
// Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange();
switch (r.GetBuiltinFunctionId()) {
case kMathImul:
return ReplaceWithPureReduction(node, ReduceMathImul(node));
default:
break;
}
return NoChange();
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_JS_BUILTIN_REDUCER_H_
#define V8_COMPILER_JS_BUILTIN_REDUCER_H_
#include "src/compiler/graph-reducer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node.h"
#include "src/compiler/simplified-operator.h"
namespace v8 {
namespace internal {
namespace compiler {
class JSBuiltinReducer FINAL : public Reducer {
public:
explicit JSBuiltinReducer(JSGraph* jsgraph)
: jsgraph_(jsgraph), simplified_(jsgraph->zone()) {}
virtual ~JSBuiltinReducer() {}
virtual Reduction Reduce(Node* node) OVERRIDE;
private:
Graph* graph() { return jsgraph_->graph(); }
CommonOperatorBuilder* common() { return jsgraph_->common(); }
MachineOperatorBuilder* machine() { return jsgraph_->machine(); }
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
Reduction ReduceMathImul(Node* node);
JSGraph* jsgraph_;
SimplifiedOperatorBuilder simplified_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_JS_BUILTIN_REDUCER_H_
......@@ -4,6 +4,7 @@
#include "src/compiler/access-builder.h"
#include "src/compiler/graph-inl.h"
#include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/node-aux-data-inl.h"
#include "src/compiler/node-properties-inl.h"
......@@ -678,6 +679,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSLoadProperty(node);
case IrOpcode::kJSStoreProperty:
return ReduceJSStoreProperty(node);
case IrOpcode::kJSCallFunction:
return JSBuiltinReducer(jsgraph()).Reduce(node);
default:
break;
}
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_OPERATOR_REDUCERS_H_
#define V8_COMPILER_OPERATOR_REDUCERS_H_
#ifndef V8_COMPILER_JS_TYPED_LOWERING_H_
#define V8_COMPILER_JS_TYPED_LOWERING_H_
#include "src/compiler/graph-reducer.h"
#include "src/compiler/js-graph.h"
......@@ -61,4 +61,4 @@ class JSTypedLowering FINAL : public Reducer {
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_OPERATOR_REDUCERS_H_
#endif // V8_COMPILER_JS_TYPED_LOWERING_H_
......@@ -54,6 +54,11 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
return graph.NewNode(common.HeapConstant(unique));
}
Node* HeapConstant(Handle<Object> constant) {
Unique<Object> unique = Unique<Object>::CreateUninitialized(constant);
return graph.NewNode(common.HeapConstant(unique));
}
Node* EmptyFrameState(Node* context) {
Node* parameters = graph.NewNode(common.StateValues(0));
Node* locals = graph.NewNode(common.StateValues(0));
......@@ -1378,3 +1383,30 @@ TEST(Int32Comparisons) {
}
}
}
TEST(BuiltinMathImul) {
JSTypedLoweringTester R;
for (size_t i = 0; i < arraysize(kNumberTypes); i++) {
for (size_t j = 0; j < arraysize(kNumberTypes); j++) {
Type* t0 = kNumberTypes[i];
Node* p0 = R.Parameter(t0, 0);
Type* t1 = kNumberTypes[j];
Node* p1 = R.Parameter(t1, 1);
Node* fun = R.HeapConstant(handle(R.isolate->context()->math_imul_fun()));
Node* call = R.graph.NewNode(R.javascript.Call(4, NO_CALL_FUNCTION_FLAGS),
fun, R.UndefinedConstant(), p0, p1);
Node* r = R.reduce(call);
if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
R.CheckPureBinop(R.machine.Int32Mul(), r);
CHECK_EQ(p0, r->InputAt(0));
CHECK_EQ(p1, r->InputAt(1));
} else {
CHECK_EQ(IrOpcode::kJSCallFunction, r->opcode());
CHECK_EQ(call, r);
}
}
}
}
......@@ -415,6 +415,8 @@
'../../src/compiler/instruction-selector.h',
'../../src/compiler/instruction.cc',
'../../src/compiler/instruction.h',
'../../src/compiler/js-builtin-reducer.cc',
'../../src/compiler/js-builtin-reducer.h',
'../../src/compiler/js-context-specialization.cc',
'../../src/compiler/js-context-specialization.h',
'../../src/compiler/js-generic-lowering.cc',
......
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