blob: a7a7da57cd63db3d071fe1387d8137b533f0eb32 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/compiler/js-builtin-reducer.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006#include "src/compiler/js-graph.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/compiler/node-matchers.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/compiler/node-properties.h"
9#include "src/compiler/simplified-operator.h"
10#include "src/objects-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/types.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018// Helper class to access JSCallFunction nodes that are potential candidates
19// for reduction when they have a BuiltinFunctionId associated with them.
20class JSCallReduction {
21 public:
22 explicit JSCallReduction(Node* node) : node_(node) {}
23
24 // Determines whether the node is a JSCallFunction operation that targets a
25 // constant callee being a well-known builtin with a BuiltinFunctionId.
26 bool HasBuiltinFunctionId() {
27 if (node_->opcode() != IrOpcode::kJSCallFunction) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
29 if (!m.HasValue() || !m.Value()->IsJSFunction()) return false;
30 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 return function->shared()->HasBuiltinFunctionId();
32 }
33
34 // Retrieves the BuiltinFunctionId as described above.
35 BuiltinFunctionId GetBuiltinFunctionId() {
36 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
38 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 return function->shared()->builtin_function_id();
40 }
41
42 // Determines whether the call takes zero inputs.
43 bool InputsMatchZero() { return GetJSCallArity() == 0; }
44
45 // Determines whether the call takes one input of the given type.
46 bool InputsMatchOne(Type* t1) {
47 return GetJSCallArity() == 1 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048 NodeProperties::GetType(GetJSCallInput(0))->Is(t1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 }
50
51 // Determines whether the call takes two inputs of the given types.
52 bool InputsMatchTwo(Type* t1, Type* t2) {
53 return GetJSCallArity() == 2 &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054 NodeProperties::GetType(GetJSCallInput(0))->Is(t1) &&
55 NodeProperties::GetType(GetJSCallInput(1))->Is(t2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056 }
57
58 // Determines whether the call takes inputs all of the given type.
59 bool InputsMatchAll(Type* t) {
60 for (int i = 0; i < GetJSCallArity(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062 return false;
63 }
64 }
65 return true;
66 }
67
68 Node* left() { return GetJSCallInput(0); }
69 Node* right() { return GetJSCallInput(1); }
70
71 int GetJSCallArity() {
72 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
73 // Skip first (i.e. callee) and second (i.e. receiver) operand.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040074 return node_->op()->ValueInputCount() - 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 }
76
77 Node* GetJSCallInput(int index) {
78 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
79 DCHECK_LT(index, GetJSCallArity());
80 // Skip first (i.e. callee) and second (i.e. receiver) operand.
81 return NodeProperties::GetValueInput(node_, index + 2);
82 }
83
84 private:
85 Node* node_;
86};
87
88
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph)
90 : AdvancedReducer(editor), jsgraph_(jsgraph) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091
92
93// ECMA-262, section 15.8.2.11.
94Reduction JSBuiltinReducer::ReduceMathMax(Node* node) {
95 JSCallReduction r(node);
96 if (r.InputsMatchZero()) {
97 // Math.max() -> -Infinity
98 return Replace(jsgraph()->Constant(-V8_INFINITY));
99 }
100 if (r.InputsMatchOne(Type::Number())) {
101 // Math.max(a:number) -> a
102 return Replace(r.left());
103 }
104 if (r.InputsMatchAll(Type::Integral32())) {
105 // Math.max(a:int32, b:int32, ...)
106 Node* value = r.GetJSCallInput(0);
107 for (int i = 1; i < r.GetJSCallArity(); i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400108 Node* const input = r.GetJSCallInput(i);
109 value = graph()->NewNode(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 common()->Select(MachineRepresentation::kNone),
111 graph()->NewNode(simplified()->NumberLessThan(), input, value), value,
112 input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 }
114 return Replace(value);
115 }
116 return NoChange();
117}
118
119
120// ES6 draft 08-24-14, section 20.2.2.19.
121Reduction JSBuiltinReducer::ReduceMathImul(Node* node) {
122 JSCallReduction r(node);
123 if (r.InputsMatchTwo(Type::Integral32(), Type::Integral32())) {
124 // Math.imul(a:int32, b:int32) -> Int32Mul(a, b)
125 Node* value = graph()->NewNode(machine()->Int32Mul(), r.left(), r.right());
126 return Replace(value);
127 }
128 return NoChange();
129}
130
131
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132// ES6 draft 08-24-14, section 20.2.2.17.
133Reduction JSBuiltinReducer::ReduceMathFround(Node* node) {
134 JSCallReduction r(node);
135 if (r.InputsMatchOne(Type::Number())) {
136 // Math.fround(a:number) -> TruncateFloat64ToFloat32(a)
137 Node* value =
138 graph()->NewNode(machine()->TruncateFloat64ToFloat32(), r.left());
139 return Replace(value);
140 }
141 return NoChange();
142}
143
144
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145Reduction JSBuiltinReducer::Reduce(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 Reduction reduction = NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 JSCallReduction r(node);
148
149 // Dispatch according to the BuiltinFunctionId if present.
150 if (!r.HasBuiltinFunctionId()) return NoChange();
151 switch (r.GetBuiltinFunctionId()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 case kMathMax:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 reduction = ReduceMathMax(node);
154 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000155 case kMathImul:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 reduction = ReduceMathImul(node);
157 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400158 case kMathFround:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 reduction = ReduceMathFround(node);
160 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 default:
162 break;
163 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164
165 // Replace builtin call assuming replacement nodes are pure values that don't
166 // produce an effect. Replaces {node} with {reduction} and relaxes effects.
167 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
168
169 return reduction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170}
171
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172
173Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
174
175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
177
178
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400179CommonOperatorBuilder* JSBuiltinReducer::common() const {
180 return jsgraph()->common();
181}
182
183
184MachineOperatorBuilder* JSBuiltinReducer::machine() const {
185 return jsgraph()->machine();
186}
187
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188
189SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
190 return jsgraph()->simplified();
191}
192
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193} // namespace compiler
194} // namespace internal
195} // namespace v8