blob: 761837576b3b40401063da876012e38ecf5eb18c [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
5#include "src/compiler/access-builder.h"
6#include "src/compiler/graph-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#include "src/compiler/js-graph.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/compiler/js-typed-lowering.h"
9#include "src/compiler/node-aux-data-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010#include "src/compiler/node-matchers.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/compiler/node-properties-inl.h"
12#include "src/types.h"
13
14namespace v8 {
15namespace internal {
16namespace compiler {
17
18// TODO(turbofan): js-typed-lowering improvements possible
19// - immediately put in type bounds for all new nodes
20// - relax effects from generic but not-side-effecting operations
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021
22
23// Relax the effects of {node} by immediately replacing effect uses of {node}
24// with the effect input to {node}.
25// TODO(turbofan): replace the effect input to {node} with {graph->start()}.
26// TODO(titzer): move into a GraphEditor?
27static void RelaxEffects(Node* node) {
28 NodeProperties::ReplaceWithValue(node, node, NULL);
29}
30
31
Emily Bernierd0a1eb72015-03-24 16:35:39 -040032JSTypedLowering::JSTypedLowering(JSGraph* jsgraph, Zone* zone)
33 : jsgraph_(jsgraph), simplified_(graph()->zone()), conversions_(zone) {
34 Handle<Object> zero = factory()->NewNumber(0.0);
35 Handle<Object> one = factory()->NewNumber(1.0);
36 zero_range_ = Type::Range(zero, zero, graph()->zone());
37 one_range_ = Type::Range(one, one, graph()->zone());
38 Handle<Object> thirtyone = factory()->NewNumber(31.0);
39 zero_thirtyone_range_ = Type::Range(zero, thirtyone, graph()->zone());
40 // TODO(jarin): Can we have a correctification of the stupid type system?
41 // These stupid work-arounds are just stupid!
42 shifted_int32_ranges_[0] = Type::Signed32();
43 if (SmiValuesAre31Bits()) {
44 shifted_int32_ranges_[1] = Type::SignedSmall();
45 for (size_t k = 2; k < arraysize(shifted_int32_ranges_); ++k) {
46 Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
47 Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
48 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
49 }
50 } else {
51 for (size_t k = 1; k < arraysize(shifted_int32_ranges_); ++k) {
52 Handle<Object> min = factory()->NewNumber(kMinInt / (1 << k));
53 Handle<Object> max = factory()->NewNumber(kMaxInt / (1 << k));
54 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
55 }
56 }
57}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058
59
60Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
61 NodeProperties::ReplaceWithValue(old, node, node);
62 return Changed(node);
63}
64
65
66// A helper class to simplify the process of reducing a single binop node with a
67// JSOperator. This class manages the rewriting of context, control, and effect
68// dependencies during lowering of a binop and contains numerous helper
69// functions for matching the types of inputs to an operation.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040070class JSBinopReduction FINAL {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 public:
72 JSBinopReduction(JSTypedLowering* lowering, Node* node)
73 : lowering_(lowering),
74 node_(node),
75 left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper),
76 right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {}
77
78 void ConvertInputsToNumber() {
79 node_->ReplaceInput(0, ConvertToNumber(left()));
80 node_->ReplaceInput(1, ConvertToNumber(right()));
81 }
82
Emily Bernierd0a1eb72015-03-24 16:35:39 -040083 void ConvertInputsToUI32(Signedness left_signedness,
84 Signedness right_signedness) {
85 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
86 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 }
88
89 void ConvertInputsToString() {
90 node_->ReplaceInput(0, ConvertToString(left()));
91 node_->ReplaceInput(1, ConvertToString(right()));
92 }
93
94 // Convert inputs for bitwise shift operation (ES5 spec 11.7).
Emily Bernierd0a1eb72015-03-24 16:35:39 -040095 void ConvertInputsForShift(Signedness left_signedness) {
96 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
97 Node* rnum = ConvertToUI32(right(), kUnsigned);
98 Type* rnum_type = NodeProperties::GetBounds(rnum).upper;
99 if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) {
100 rnum = graph()->NewNode(machine()->Word32And(), rnum,
101 jsgraph()->Int32Constant(0x1F));
102 }
103 node_->ReplaceInput(1, rnum);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 }
105
106 void SwapInputs() {
107 Node* l = left();
108 Node* r = right();
109 node_->ReplaceInput(0, r);
110 node_->ReplaceInput(1, l);
111 std::swap(left_type_, right_type_);
112 }
113
114 // Remove all effect and control inputs and outputs to this node and change
115 // to the pure operator {op}, possibly inserting a boolean inversion.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400116 Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
117 Type* type = Type::Any()) {
118 DCHECK_EQ(0, op->EffectInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400120 DCHECK_EQ(0, op->ControlInputCount());
121 DCHECK_EQ(2, op->ValueInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122
123 // Remove the effects from the node, if any, and update its effect usages.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124 if (node_->op()->EffectInputCount() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 RelaxEffects(node_);
126 }
127 // Remove the inputs corresponding to context, effect, and control.
128 NodeProperties::RemoveNonValueInputs(node_);
129 // Finally, update the operator to the new one.
130 node_->set_op(op);
131
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132 // TODO(jarin): Replace the explicit typing hack with a call to some method
133 // that encapsulates changing the operator and re-typing.
134 Bounds const bounds = NodeProperties::GetBounds(node_);
135 NodeProperties::SetBounds(node_, Bounds::NarrowUpper(bounds, type, zone()));
136
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137 if (invert) {
138 // Insert an boolean not to invert the value.
139 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
140 node_->ReplaceUses(value);
141 // Note: ReplaceUses() smashes all uses, so smash it back here.
142 value->ReplaceInput(0, node_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400143 return lowering_->Replace(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 }
145 return lowering_->Changed(node_);
146 }
147
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400148 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
149 return ChangeToPureOperator(op, false, type);
150 }
151
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); }
153
154 bool BothInputsAre(Type* t) {
155 return left_type_->Is(t) && right_type_->Is(t);
156 }
157
158 bool OneInputCannotBe(Type* t) {
159 return !left_type_->Maybe(t) || !right_type_->Maybe(t);
160 }
161
162 bool NeitherInputCanBe(Type* t) {
163 return !left_type_->Maybe(t) && !right_type_->Maybe(t);
164 }
165
166 Node* effect() { return NodeProperties::GetEffectInput(node_); }
167 Node* control() { return NodeProperties::GetControlInput(node_); }
168 Node* context() { return NodeProperties::GetContextInput(node_); }
169 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
170 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
171 Type* left_type() { return left_type_; }
172 Type* right_type() { return right_type_; }
173
174 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 Graph* graph() const { return lowering_->graph(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 JSGraph* jsgraph() { return lowering_->jsgraph(); }
177 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
178 MachineOperatorBuilder* machine() { return lowering_->machine(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400179 Zone* zone() const { return graph()->zone(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180
181 private:
182 JSTypedLowering* lowering_; // The containing lowering instance.
183 Node* node_; // The original node.
184 Type* left_type_; // Cache of the left input's type.
185 Type* right_type_; // Cache of the right input's type.
186
187 Node* ConvertToString(Node* node) {
188 // Avoid introducing too many eager ToString() operations.
189 Reduction reduced = lowering_->ReduceJSToStringInput(node);
190 if (reduced.Changed()) return reduced.replacement();
191 Node* n = graph()->NewNode(javascript()->ToString(), node, context(),
192 effect(), control());
193 update_effect(n);
194 return n;
195 }
196
197 Node* ConvertToNumber(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400198 if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) {
199 return lowering_->ConvertToNumber(node);
200 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 Node* n = graph()->NewNode(javascript()->ToNumber(), node, context(),
202 effect(), control());
203 update_effect(n);
204 return n;
205 }
206
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400207 Node* ConvertToUI32(Node* node, Signedness signedness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 // Avoid introducing too many eager NumberToXXnt32() operations.
209 node = ConvertToNumber(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210 Type* type = NodeProperties::GetBounds(node).upper;
211 if (signedness == kSigned) {
212 if (!type->Is(Type::Signed32())) {
213 node = graph()->NewNode(simplified()->NumberToInt32(), node);
214 }
215 } else {
216 DCHECK_EQ(kUnsigned, signedness);
217 if (!type->Is(Type::Unsigned32())) {
218 node = graph()->NewNode(simplified()->NumberToUint32(), node);
219 }
220 }
221 return node;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 }
223
224 void update_effect(Node* effect) {
225 NodeProperties::ReplaceEffectInput(node_, effect);
226 }
227};
228
229
230Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
231 JSBinopReduction r(this, node);
232 if (r.BothInputsAre(Type::Number())) {
233 // JSAdd(x:number, y:number) => NumberAdd(x, y)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400234 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400236 if (r.BothInputsAre(Type::Primitive()) &&
237 r.NeitherInputCanBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000238 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
239 r.ConvertInputsToNumber();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400240 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241 }
242#if 0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243 // TODO(turbofan): General ToNumber disabled for now because:
244 // a) The inserted ToNumber operation screws up observability of valueOf.
245 // b) Deoptimization at ToNumber doesn't have corresponding bailout id.
246 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
247 if (r.NeitherInputCanBe(maybe_string)) {
248 ...
249 }
250#endif
251#if 0
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 // TODO(turbofan): Lowering of StringAdd is disabled for now because:
253 // a) The inserted ToString operation screws up valueOf vs. toString order.
254 // b) Deoptimization at ToString doesn't have corresponding bailout id.
255 // c) Our current StringAddStub is actually non-pure and requires context.
256 if (r.OneInputIs(Type::String())) {
257 // JSAdd(x:string, y:string) => StringAdd(x, y)
258 // JSAdd(x:string, y) => StringAdd(x, ToString(y))
259 // JSAdd(x, y:string) => StringAdd(ToString(x), y)
260 r.ConvertInputsToString();
261 return r.ChangeToPureOperator(simplified()->StringAdd());
262 }
263#endif
264 return NoChange();
265}
266
267
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400268Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) {
269 JSBinopReduction r(this, node);
270 if (r.BothInputsAre(Type::Primitive()) || r.OneInputIs(zero_range_)) {
271 // TODO(jarin): Propagate frame state input from non-primitive input node to
272 // JSToNumber node.
273 // TODO(titzer): some Smi bitwise operations don't really require going
274 // all the way to int32, which can save tagging/untagging for some
275 // operations
276 // on some platforms.
277 // TODO(turbofan): make this heuristic configurable for code size.
278 r.ConvertInputsToUI32(kSigned, kSigned);
279 return r.ChangeToPureOperator(machine()->Word32Or(), Type::Integral32());
280 }
281 return NoChange();
282}
283
284
285Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
286 JSBinopReduction r(this, node);
287 if (r.BothInputsAre(Type::Primitive()) || r.OneInputIs(one_range_)) {
288 // TODO(jarin): Propagate frame state input from non-primitive input node to
289 // JSToNumber node.
290 r.ConvertInputsToNumber();
291 return r.ChangeToPureOperator(simplified()->NumberMultiply(),
292 Type::Number());
293 }
294 // TODO(turbofan): relax/remove the effects of this operator in other cases.
295 return NoChange();
296}
297
298
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
300 const Operator* numberOp) {
301 JSBinopReduction r(this, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400302 if (r.BothInputsAre(Type::Primitive())) {
303 r.ConvertInputsToNumber();
304 return r.ChangeToPureOperator(numberOp, Type::Number());
305 }
306#if 0
307 // TODO(turbofan): General ToNumber disabled for now because:
308 // a) The inserted ToNumber operation screws up observability of valueOf.
309 // b) Deoptimization at ToNumber doesn't have corresponding bailout id.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 if (r.OneInputIs(Type::Primitive())) {
311 // If at least one input is a primitive, then insert appropriate conversions
312 // to number and reduce this operator to the given numeric one.
313 // TODO(turbofan): make this heuristic configurable for code size.
314 r.ConvertInputsToNumber();
315 return r.ChangeToPureOperator(numberOp);
316 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 // TODO(turbofan): relax/remove the effects of this operator in other cases.
319 return NoChange();
320}
321
322
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400323Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324 JSBinopReduction r(this, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400325 if (r.BothInputsAre(Type::Primitive())) {
326 // TODO(titzer): some Smi bitwise operations don't really require going
327 // all the way to int32, which can save tagging/untagging for some
328 // operations
329 // on some platforms.
330 // TODO(turbofan): make this heuristic configurable for code size.
331 r.ConvertInputsToUI32(kSigned, kSigned);
332 return r.ChangeToPureOperator(intOp, Type::Integral32());
333 }
334 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335}
336
337
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
339 Signedness left_signedness,
340 const Operator* shift_op) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 JSBinopReduction r(this, node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400342 if (r.BothInputsAre(Type::Primitive())) {
343 r.ConvertInputsForShift(left_signedness);
344 return r.ChangeToPureOperator(shift_op, Type::Integral32());
345 }
346 return NoChange();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000347}
348
349
350Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
351 JSBinopReduction r(this, node);
352 if (r.BothInputsAre(Type::String())) {
353 // If both inputs are definitely strings, perform a string comparison.
354 const Operator* stringOp;
355 switch (node->opcode()) {
356 case IrOpcode::kJSLessThan:
357 stringOp = simplified()->StringLessThan();
358 break;
359 case IrOpcode::kJSGreaterThan:
360 stringOp = simplified()->StringLessThan();
361 r.SwapInputs(); // a > b => b < a
362 break;
363 case IrOpcode::kJSLessThanOrEqual:
364 stringOp = simplified()->StringLessThanOrEqual();
365 break;
366 case IrOpcode::kJSGreaterThanOrEqual:
367 stringOp = simplified()->StringLessThanOrEqual();
368 r.SwapInputs(); // a >= b => b <= a
369 break;
370 default:
371 return NoChange();
372 }
373 return r.ChangeToPureOperator(stringOp);
374 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400375#if 0
376 // TODO(turbofan): General ToNumber disabled for now because:
377 // a) The inserted ToNumber operation screws up observability of valueOf.
378 // b) Deoptimization at ToNumber doesn't have corresponding bailout id.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379 Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
380 if (r.OneInputCannotBe(maybe_string)) {
381 // If one input cannot be a string, then emit a number comparison.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400382 ...
383 }
384#endif
385 if (r.BothInputsAre(Type::Primitive()) &&
386 r.OneInputCannotBe(Type::StringOrReceiver())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 const Operator* less_than;
388 const Operator* less_than_or_equal;
389 if (r.BothInputsAre(Type::Unsigned32())) {
390 less_than = machine()->Uint32LessThan();
391 less_than_or_equal = machine()->Uint32LessThanOrEqual();
392 } else if (r.BothInputsAre(Type::Signed32())) {
393 less_than = machine()->Int32LessThan();
394 less_than_or_equal = machine()->Int32LessThanOrEqual();
395 } else {
396 // TODO(turbofan): mixed signed/unsigned int32 comparisons.
397 r.ConvertInputsToNumber();
398 less_than = simplified()->NumberLessThan();
399 less_than_or_equal = simplified()->NumberLessThanOrEqual();
400 }
401 const Operator* comparison;
402 switch (node->opcode()) {
403 case IrOpcode::kJSLessThan:
404 comparison = less_than;
405 break;
406 case IrOpcode::kJSGreaterThan:
407 comparison = less_than;
408 r.SwapInputs(); // a > b => b < a
409 break;
410 case IrOpcode::kJSLessThanOrEqual:
411 comparison = less_than_or_equal;
412 break;
413 case IrOpcode::kJSGreaterThanOrEqual:
414 comparison = less_than_or_equal;
415 r.SwapInputs(); // a >= b => b <= a
416 break;
417 default:
418 return NoChange();
419 }
420 return r.ChangeToPureOperator(comparison);
421 }
422 // TODO(turbofan): relax/remove effects of this operator in other cases.
423 return NoChange(); // Keep a generic comparison.
424}
425
426
427Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
428 JSBinopReduction r(this, node);
429
430 if (r.BothInputsAre(Type::Number())) {
431 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
432 }
433 if (r.BothInputsAre(Type::String())) {
434 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
435 }
436 if (r.BothInputsAre(Type::Receiver())) {
437 return r.ChangeToPureOperator(
438 simplified()->ReferenceEqual(Type::Receiver()), invert);
439 }
440 // TODO(turbofan): js-typed-lowering of Equal(undefined)
441 // TODO(turbofan): js-typed-lowering of Equal(null)
442 // TODO(turbofan): js-typed-lowering of Equal(boolean)
443 return NoChange();
444}
445
446
447Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
448 JSBinopReduction r(this, node);
449 if (r.left() == r.right()) {
450 // x === x is always true if x != NaN
451 if (!r.left_type()->Maybe(Type::NaN())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400452 return ReplaceEagerly(node, jsgraph()->BooleanConstant(!invert));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000453 }
454 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400455 if (r.OneInputCannotBe(Type::NumberOrString())) {
456 // For values with canonical representation (i.e. not string nor number) an
457 // empty type intersection means the values cannot be strictly equal.
458 if (!r.left_type()->Maybe(r.right_type())) {
459 return ReplaceEagerly(node, jsgraph()->BooleanConstant(invert));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000460 }
461 }
462 if (r.OneInputIs(Type::Undefined())) {
463 return r.ChangeToPureOperator(
464 simplified()->ReferenceEqual(Type::Undefined()), invert);
465 }
466 if (r.OneInputIs(Type::Null())) {
467 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Null()),
468 invert);
469 }
470 if (r.OneInputIs(Type::Boolean())) {
471 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Boolean()),
472 invert);
473 }
474 if (r.OneInputIs(Type::Object())) {
475 return r.ChangeToPureOperator(simplified()->ReferenceEqual(Type::Object()),
476 invert);
477 }
478 if (r.OneInputIs(Type::Receiver())) {
479 return r.ChangeToPureOperator(
480 simplified()->ReferenceEqual(Type::Receiver()), invert);
481 }
482 if (r.BothInputsAre(Type::String())) {
483 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
484 }
485 if (r.BothInputsAre(Type::Number())) {
486 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
487 }
488 // TODO(turbofan): js-typed-lowering of StrictEqual(mixed types)
489 return NoChange();
490}
491
492
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400493Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) {
494 Node* input = node->InputAt(0);
495 Type* input_type = NodeProperties::GetBounds(input).upper;
496 if (input_type->Is(Type::Boolean())) {
497 // JSUnaryNot(x:boolean,context) => BooleanNot(x)
498 node->set_op(simplified()->BooleanNot());
499 node->TrimInputCount(1);
500 return Changed(node);
501 }
502 // JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x))
503 node->set_op(simplified()->BooleanNot());
504 node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input));
505 node->TrimInputCount(1);
506 return Changed(node);
507}
508
509
510Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
511 Node* input = node->InputAt(0);
512 Type* input_type = NodeProperties::GetBounds(input).upper;
513 if (input_type->Is(Type::Boolean())) {
514 // JSToBoolean(x:boolean,context) => x
515 return Replace(input);
516 }
517 // JSToBoolean(x,context) => AnyToBoolean(x)
518 node->set_op(simplified()->AnyToBoolean());
519 node->TrimInputCount(1);
520 return Changed(node);
521}
522
523
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
525 if (input->opcode() == IrOpcode::kJSToNumber) {
526 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400527 Reduction result = ReduceJSToNumber(input);
528 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 return Changed(input); // JSToNumber(JSToNumber(x)) => JSToNumber(x)
530 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400531 // Check if we have a cached conversion.
532 Node* conversion = FindConversion<IrOpcode::kJSToNumber>(input);
533 if (conversion) return Replace(conversion);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 Type* input_type = NodeProperties::GetBounds(input).upper;
535 if (input_type->Is(Type::Number())) {
536 // JSToNumber(x:number) => x
537 return Changed(input);
538 }
539 if (input_type->Is(Type::Undefined())) {
540 // JSToNumber(undefined) => #NaN
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400541 return Replace(jsgraph()->NaNConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542 }
543 if (input_type->Is(Type::Null())) {
544 // JSToNumber(null) => #0
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400545 return Replace(jsgraph()->ZeroConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546 }
547 if (input_type->Is(Type::Boolean())) {
548 // JSToNumber(x:boolean) => BooleanToNumber(x)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400549 return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 }
551 // TODO(turbofan): js-typed-lowering of ToNumber(x:string)
552 return NoChange();
553}
554
555
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400556Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
557 // Try to reduce the input first.
558 Node* const input = node->InputAt(0);
559 Reduction reduction = ReduceJSToNumberInput(input);
560 if (reduction.Changed()) {
561 NodeProperties::ReplaceWithValue(node, reduction.replacement());
562 return reduction;
563 }
564 Type* const input_type = NodeProperties::GetBounds(input).upper;
565 if (input_type->Is(Type::PlainPrimitive())) {
566 if (input->opcode() == IrOpcode::kPhi) {
567 // JSToNumber(phi(x1,...,xn,control):plain-primitive,context)
568 // => phi(JSToNumber(x1,no-context),
569 // ...,
570 // JSToNumber(xn,no-context),control)
571 int const input_count = input->InputCount() - 1;
572 Node* const control = input->InputAt(input_count);
573 DCHECK_LE(0, input_count);
574 DCHECK(NodeProperties::IsControl(control));
575 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
576 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
577 RelaxEffects(node);
578 node->set_op(common()->Phi(kMachAnyTagged, input_count));
579 for (int i = 0; i < input_count; ++i) {
580 // We must be very careful not to introduce cycles when pushing
581 // operations into phis. It is safe for {value}, since it appears
582 // as input to the phi that we are replacing, but it's not safe
583 // to simply reuse the context of the {node}. However, ToNumber()
584 // does not require a context anyways, so it's safe to discard it
585 // here and pass the dummy context.
586 Node* const value = ConvertToNumber(input->InputAt(i));
587 if (i < node->InputCount()) {
588 node->ReplaceInput(i, value);
589 } else {
590 node->AppendInput(graph()->zone(), value);
591 }
592 }
593 if (input_count < node->InputCount()) {
594 node->ReplaceInput(input_count, control);
595 } else {
596 node->AppendInput(graph()->zone(), control);
597 }
598 node->TrimInputCount(input_count + 1);
599 return Changed(node);
600 }
601 if (input->opcode() == IrOpcode::kSelect) {
602 // JSToNumber(select(c,x1,x2):plain-primitive,context)
603 // => select(c,JSToNumber(x1,no-context),JSToNumber(x2,no-context))
604 int const input_count = input->InputCount();
605 BranchHint const input_hint = SelectParametersOf(input->op()).hint();
606 DCHECK_EQ(3, input_count);
607 DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Number()));
608 DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Number()));
609 RelaxEffects(node);
610 node->set_op(common()->Select(kMachAnyTagged, input_hint));
611 node->ReplaceInput(0, input->InputAt(0));
612 for (int i = 1; i < input_count; ++i) {
613 // We must be very careful not to introduce cycles when pushing
614 // operations into selects. It is safe for {value}, since it appears
615 // as input to the select that we are replacing, but it's not safe
616 // to simply reuse the context of the {node}. However, ToNumber()
617 // does not require a context anyways, so it's safe to discard it
618 // here and pass the dummy context.
619 Node* const value = ConvertToNumber(input->InputAt(i));
620 node->ReplaceInput(i, value);
621 }
622 node->TrimInputCount(input_count);
623 return Changed(node);
624 }
625 // Remember this conversion.
626 InsertConversion(node);
627 if (node->InputAt(1) != jsgraph()->NoContextConstant() ||
628 node->InputAt(2) != graph()->start() ||
629 node->InputAt(3) != graph()->start()) {
630 // JSToNumber(x:plain-primitive,context,effect,control)
631 // => JSToNumber(x,no-context,start,start)
632 RelaxEffects(node);
633 node->ReplaceInput(1, jsgraph()->NoContextConstant());
634 node->ReplaceInput(2, graph()->start());
635 node->ReplaceInput(3, graph()->start());
636 return Changed(node);
637 }
638 }
639 return NoChange();
640}
641
642
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
644 if (input->opcode() == IrOpcode::kJSToString) {
645 // Recursively try to reduce the input first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400646 Reduction result = ReduceJSToString(input);
647 if (result.Changed()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000648 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
649 }
650 Type* input_type = NodeProperties::GetBounds(input).upper;
651 if (input_type->Is(Type::String())) {
652 return Changed(input); // JSToString(x:string) => x
653 }
654 if (input_type->Is(Type::Undefined())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400655 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 }
657 if (input_type->Is(Type::Null())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400658 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000659 }
660 // TODO(turbofan): js-typed-lowering of ToString(x:boolean)
661 // TODO(turbofan): js-typed-lowering of ToString(x:number)
662 return NoChange();
663}
664
665
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400666Reduction JSTypedLowering::ReduceJSToString(Node* node) {
667 // Try to reduce the input first.
668 Node* const input = node->InputAt(0);
669 Reduction reduction = ReduceJSToStringInput(input);
670 if (reduction.Changed()) {
671 NodeProperties::ReplaceWithValue(node, reduction.replacement());
672 return reduction;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 return NoChange();
675}
676
677
678Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
679 Node* key = NodeProperties::GetValueInput(node, 1);
680 Node* base = NodeProperties::GetValueInput(node, 0);
681 Type* key_type = NodeProperties::GetBounds(key).upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000682 // TODO(mstarzinger): This lowering is not correct if:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400683 // a) The typed array or it's buffer is neutered.
684 HeapObjectMatcher<Object> mbase(base);
685 if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
686 Handle<JSTypedArray> const array =
687 Handle<JSTypedArray>::cast(mbase.Value().handle());
688 array->GetBuffer()->set_is_neuterable(false);
689 BufferAccess const access(array->type());
690 size_t const k = ElementSizeLog2Of(access.machine_type());
691 double const byte_length = array->byte_length()->Number();
692 CHECK_LT(k, arraysize(shifted_int32_ranges_));
693 if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
694 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
695 // JSLoadProperty(typed-array, int32)
696 Handle<ExternalArray> elements =
697 Handle<ExternalArray>::cast(handle(array->elements()));
698 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
699 Node* length = jsgraph()->Constant(byte_length);
700 Node* effect = NodeProperties::GetEffectInput(node);
701 Node* control = NodeProperties::GetControlInput(node);
702 // Check if we can avoid the bounds check.
703 if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) {
704 Node* load = graph()->NewNode(
705 simplified()->LoadElement(
706 AccessBuilder::ForTypedArrayElement(array->type(), true)),
707 buffer, key, effect, control);
708 return ReplaceEagerly(node, load);
709 }
710 // Compute byte offset.
711 Node* offset = Word32Shl(key, static_cast<int>(k));
712 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
713 offset, length, effect, control);
714 return ReplaceEagerly(node, load);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716 }
717 return NoChange();
718}
719
720
721Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
722 Node* key = NodeProperties::GetValueInput(node, 1);
723 Node* base = NodeProperties::GetValueInput(node, 0);
724 Node* value = NodeProperties::GetValueInput(node, 2);
725 Type* key_type = NodeProperties::GetBounds(key).upper;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400726 Type* value_type = NodeProperties::GetBounds(value).upper;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000727 // TODO(mstarzinger): This lowering is not correct if:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400728 // a) The typed array or its buffer is neutered.
729 HeapObjectMatcher<Object> mbase(base);
730 if (mbase.HasValue() && mbase.Value().handle()->IsJSTypedArray()) {
731 Handle<JSTypedArray> const array =
732 Handle<JSTypedArray>::cast(mbase.Value().handle());
733 array->GetBuffer()->set_is_neuterable(false);
734 BufferAccess const access(array->type());
735 size_t const k = ElementSizeLog2Of(access.machine_type());
736 double const byte_length = array->byte_length()->Number();
737 CHECK_LT(k, arraysize(shifted_int32_ranges_));
738 if (IsExternalArrayElementsKind(array->map()->elements_kind()) &&
739 access.external_array_type() != kExternalUint8ClampedArray &&
740 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
741 // JSLoadProperty(typed-array, int32)
742 Handle<ExternalArray> elements =
743 Handle<ExternalArray>::cast(handle(array->elements()));
744 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
745 Node* length = jsgraph()->Constant(byte_length);
746 Node* context = NodeProperties::GetContextInput(node);
747 Node* effect = NodeProperties::GetEffectInput(node);
748 Node* control = NodeProperties::GetControlInput(node);
749 // Convert to a number first.
750 if (!value_type->Is(Type::Number())) {
751 Reduction number_reduction = ReduceJSToNumberInput(value);
752 if (number_reduction.Changed()) {
753 value = number_reduction.replacement();
754 } else {
755 value = effect = graph()->NewNode(javascript()->ToNumber(), value,
756 context, effect, control);
757 }
758 }
759 // For integer-typed arrays, convert to the integer type.
760 if (TypeOf(access.machine_type()) == kTypeInt32 &&
761 !value_type->Is(Type::Signed32())) {
762 value = graph()->NewNode(simplified()->NumberToInt32(), value);
763 } else if (TypeOf(access.machine_type()) == kTypeUint32 &&
764 !value_type->Is(Type::Unsigned32())) {
765 value = graph()->NewNode(simplified()->NumberToUint32(), value);
766 }
767 // Check if we can avoid the bounds check.
768 if (key_type->Min() >= 0 && key_type->Max() < array->length()->Number()) {
769 node->set_op(simplified()->StoreElement(
770 AccessBuilder::ForTypedArrayElement(array->type(), true)));
771 node->ReplaceInput(0, buffer);
772 DCHECK_EQ(key, node->InputAt(1));
773 node->ReplaceInput(2, value);
774 node->ReplaceInput(3, effect);
775 node->ReplaceInput(4, control);
776 node->TrimInputCount(5);
777 return Changed(node);
778 }
779 // Compute byte offset.
780 Node* offset = Word32Shl(key, static_cast<int>(k));
781 // Turn into a StoreBuffer operation.
782 node->set_op(simplified()->StoreBuffer(access));
783 node->ReplaceInput(0, buffer);
784 node->ReplaceInput(1, offset);
785 node->ReplaceInput(2, length);
786 node->ReplaceInput(3, value);
787 node->ReplaceInput(4, effect);
788 DCHECK_EQ(control, node->InputAt(5));
789 DCHECK_EQ(6, node->InputCount());
790 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000791 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792 }
793 return NoChange();
794}
795
796
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400797Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
798 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
799 ContextAccess const& access = ContextAccessOf(node->op());
800 Node* const effect = NodeProperties::GetEffectInput(node);
801 Node* const control = graph()->start();
802 for (size_t i = 0; i < access.depth(); ++i) {
803 node->ReplaceInput(
804 0, graph()->NewNode(
805 simplified()->LoadField(
806 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
807 NodeProperties::GetValueInput(node, 0), effect, control));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400809 node->set_op(
810 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
811 node->ReplaceInput(1, effect);
812 node->ReplaceInput(2, control);
813 DCHECK_EQ(3, node->InputCount());
814 return Changed(node);
815}
816
817
818Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
819 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
820 ContextAccess const& access = ContextAccessOf(node->op());
821 Node* const effect = NodeProperties::GetEffectInput(node);
822 Node* const control = graph()->start();
823 for (size_t i = 0; i < access.depth(); ++i) {
824 node->ReplaceInput(
825 0, graph()->NewNode(
826 simplified()->LoadField(
827 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
828 NodeProperties::GetValueInput(node, 0), effect, control));
829 }
830 node->set_op(
831 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
832 node->RemoveInput(2);
833 DCHECK_EQ(4, node->InputCount());
834 return Changed(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000835}
836
837
838Reduction JSTypedLowering::Reduce(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400839 // Check if the output type is a singleton. In that case we already know the
840 // result value and can simply replace the node if it's eliminable.
841 if (NodeProperties::IsTyped(node) &&
842 !IrOpcode::IsLeafOpcode(node->opcode()) &&
843 node->op()->HasProperty(Operator::kEliminatable)) {
844 Type* upper = NodeProperties::GetBounds(node).upper;
845 if (upper->IsConstant()) {
846 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value());
847 NodeProperties::ReplaceWithValue(node, replacement);
848 return Changed(replacement);
849 } else if (upper->Is(Type::MinusZero())) {
850 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value());
851 NodeProperties::ReplaceWithValue(node, replacement);
852 return Changed(replacement);
853 } else if (upper->Is(Type::NaN())) {
854 Node* replacement = jsgraph()->NaNConstant();
855 NodeProperties::ReplaceWithValue(node, replacement);
856 return Changed(replacement);
857 } else if (upper->Is(Type::Null())) {
858 Node* replacement = jsgraph()->NullConstant();
859 NodeProperties::ReplaceWithValue(node, replacement);
860 return Changed(replacement);
861 } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) {
862 Node* replacement = jsgraph()->Constant(upper->Min());
863 NodeProperties::ReplaceWithValue(node, replacement);
864 return Changed(replacement);
865 } else if (upper->Is(Type::Undefined())) {
866 Node* replacement = jsgraph()->UndefinedConstant();
867 NodeProperties::ReplaceWithValue(node, replacement);
868 return Changed(replacement);
869 }
870 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871 switch (node->opcode()) {
872 case IrOpcode::kJSEqual:
873 return ReduceJSEqual(node, false);
874 case IrOpcode::kJSNotEqual:
875 return ReduceJSEqual(node, true);
876 case IrOpcode::kJSStrictEqual:
877 return ReduceJSStrictEqual(node, false);
878 case IrOpcode::kJSStrictNotEqual:
879 return ReduceJSStrictEqual(node, true);
880 case IrOpcode::kJSLessThan: // fall through
881 case IrOpcode::kJSGreaterThan: // fall through
882 case IrOpcode::kJSLessThanOrEqual: // fall through
883 case IrOpcode::kJSGreaterThanOrEqual:
884 return ReduceJSComparison(node);
885 case IrOpcode::kJSBitwiseOr:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400886 return ReduceJSBitwiseOr(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000887 case IrOpcode::kJSBitwiseXor:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400888 return ReduceInt32Binop(node, machine()->Word32Xor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889 case IrOpcode::kJSBitwiseAnd:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400890 return ReduceInt32Binop(node, machine()->Word32And());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 case IrOpcode::kJSShiftLeft:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400892 return ReduceUI32Shift(node, kSigned, machine()->Word32Shl());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893 case IrOpcode::kJSShiftRight:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400894 return ReduceUI32Shift(node, kSigned, machine()->Word32Sar());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895 case IrOpcode::kJSShiftRightLogical:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400896 return ReduceUI32Shift(node, kUnsigned, machine()->Word32Shr());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000897 case IrOpcode::kJSAdd:
898 return ReduceJSAdd(node);
899 case IrOpcode::kJSSubtract:
900 return ReduceNumberBinop(node, simplified()->NumberSubtract());
901 case IrOpcode::kJSMultiply:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400902 return ReduceJSMultiply(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000903 case IrOpcode::kJSDivide:
904 return ReduceNumberBinop(node, simplified()->NumberDivide());
905 case IrOpcode::kJSModulus:
906 return ReduceNumberBinop(node, simplified()->NumberModulus());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400907 case IrOpcode::kJSUnaryNot:
908 return ReduceJSUnaryNot(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000909 case IrOpcode::kJSToBoolean:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400910 return ReduceJSToBoolean(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000911 case IrOpcode::kJSToNumber:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400912 return ReduceJSToNumber(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000913 case IrOpcode::kJSToString:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400914 return ReduceJSToString(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000915 case IrOpcode::kJSLoadProperty:
916 return ReduceJSLoadProperty(node);
917 case IrOpcode::kJSStoreProperty:
918 return ReduceJSStoreProperty(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400919 case IrOpcode::kJSLoadContext:
920 return ReduceJSLoadContext(node);
921 case IrOpcode::kJSStoreContext:
922 return ReduceJSStoreContext(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000923 default:
924 break;
925 }
926 return NoChange();
927}
928
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400929
930Node* JSTypedLowering::ConvertToNumber(Node* input) {
931 DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
932 // Avoid inserting too many eager ToNumber() operations.
933 Reduction const reduction = ReduceJSToNumberInput(input);
934 if (reduction.Changed()) return reduction.replacement();
935 Node* const conversion = graph()->NewNode(javascript()->ToNumber(), input,
936 jsgraph()->NoContextConstant(),
937 graph()->start(), graph()->start());
938 InsertConversion(conversion);
939 return conversion;
940}
941
942
943template <IrOpcode::Value kOpcode>
944Node* JSTypedLowering::FindConversion(Node* input) {
945 size_t const input_id = input->id();
946 if (input_id < conversions_.size()) {
947 Node* const conversion = conversions_[input_id];
948 if (conversion && conversion->opcode() == kOpcode) {
949 return conversion;
950 }
951 }
952 return nullptr;
953}
954
955
956void JSTypedLowering::InsertConversion(Node* conversion) {
957 DCHECK(conversion->opcode() == IrOpcode::kJSToNumber);
958 size_t const input_id = conversion->InputAt(0)->id();
959 if (input_id >= conversions_.size()) {
960 conversions_.resize(2 * input_id + 1);
961 }
962 conversions_[input_id] = conversion;
963}
964
965
966Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
967 if (rhs == 0) return lhs;
968 return graph()->NewNode(machine()->Word32Shl(), lhs,
969 jsgraph()->Int32Constant(rhs));
970}
971
972
973Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
974
975
976Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
977
978
979JSOperatorBuilder* JSTypedLowering::javascript() const {
980 return jsgraph()->javascript();
981}
982
983
984CommonOperatorBuilder* JSTypedLowering::common() const {
985 return jsgraph()->common();
986}
987
988
989MachineOperatorBuilder* JSTypedLowering::machine() const {
990 return jsgraph()->machine();
991}
992
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000993} // namespace compiler
994} // namespace internal
995} // namespace v8