js-builtin-reducer.cc revision f2e3994fa5148cc3d9946666f0b0596290192b0e
1// 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
5#include "src/compiler/js-builtin-reducer.h"
6#include "src/compiler/js-graph.h"
7#include "src/compiler/node-matchers.h"
8#include "src/compiler/node-properties.h"
9#include "src/compiler/simplified-operator.h"
10#include "src/objects-inl.h"
11#include "src/types.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17
18// 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;
28    HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
29    if (!m.HasValue() || !m.Value()->IsJSFunction()) return false;
30    Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
31    return function->shared()->HasBuiltinFunctionId();
32  }
33
34  // Retrieves the BuiltinFunctionId as described above.
35  BuiltinFunctionId GetBuiltinFunctionId() {
36    DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode());
37    HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
38    Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
39    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 &&
48           NodeProperties::GetType(GetJSCallInput(0))->Is(t1);
49  }
50
51  // Determines whether the call takes two inputs of the given types.
52  bool InputsMatchTwo(Type* t1, Type* t2) {
53    return GetJSCallArity() == 2 &&
54           NodeProperties::GetType(GetJSCallInput(0))->Is(t1) &&
55           NodeProperties::GetType(GetJSCallInput(1))->Is(t2);
56  }
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++) {
61      if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) {
62        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.
74    return node_->op()->ValueInputCount() - 2;
75  }
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
89JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph)
90    : AdvancedReducer(editor), jsgraph_(jsgraph) {}
91
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++) {
108      Node* const input = r.GetJSCallInput(i);
109      value = graph()->NewNode(
110          common()->Select(MachineRepresentation::kNone),
111          graph()->NewNode(simplified()->NumberLessThan(), input, value), value,
112          input);
113    }
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
132// 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
145Reduction JSBuiltinReducer::Reduce(Node* node) {
146  Reduction reduction = NoChange();
147  JSCallReduction r(node);
148
149  // Dispatch according to the BuiltinFunctionId if present.
150  if (!r.HasBuiltinFunctionId()) return NoChange();
151  switch (r.GetBuiltinFunctionId()) {
152    case kMathMax:
153      reduction = ReduceMathMax(node);
154      break;
155    case kMathImul:
156      reduction = ReduceMathImul(node);
157      break;
158    case kMathFround:
159      reduction = ReduceMathFround(node);
160      break;
161    default:
162      break;
163  }
164
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;
170}
171
172
173Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
174
175
176Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
177
178
179CommonOperatorBuilder* JSBuiltinReducer::common() const {
180  return jsgraph()->common();
181}
182
183
184MachineOperatorBuilder* JSBuiltinReducer::machine() const {
185  return jsgraph()->machine();
186}
187
188
189SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
190  return jsgraph()->simplified();
191}
192
193}  // namespace compiler
194}  // namespace internal
195}  // namespace v8
196