blob: 1461709dabf9ab2c533e2dfe12e7039d4a993f12 [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/simplified-lowering.h"
6
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#include <limits>
8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/base/bits.h"
10#include "src/code-factory.h"
11#include "src/compiler/common-operator.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/compiler/diamond.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/compiler/graph-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014#include "src/compiler/linkage.h"
15#include "src/compiler/node-matchers.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016#include "src/compiler/node-properties-inl.h"
17#include "src/compiler/representation-change.h"
18#include "src/compiler/simplified-lowering.h"
19#include "src/compiler/simplified-operator.h"
20#include "src/objects.h"
21
22namespace v8 {
23namespace internal {
24namespace compiler {
25
26// Macro for outputting trace information from representation inference.
27#define TRACE(x) \
28 if (FLAG_trace_representation) PrintF x
29
30// Representation selection and lowering of {Simplified} operators to machine
31// operators are interwined. We use a fixpoint calculation to compute both the
32// output representation and the best possible lowering for {Simplified} nodes.
33// Representation change insertion ensures that all values are in the correct
34// machine representation after this phase, as dictated by the machine
35// operators themselves.
36enum Phase {
37 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
38 // backwards from uses to definitions, around cycles in phis, according
39 // to local rules for each operator.
40 // During this phase, the usage information for a node determines the best
41 // possible lowering for each operator so far, and that in turn determines
42 // the output representation.
43 // Therefore, to be correct, this phase must iterate to a fixpoint before
44 // the next phase can begin.
45 PROPAGATE,
46
47 // 2.) LOWER: perform lowering for all {Simplified} nodes by replacing some
48 // operators for some nodes, expanding some nodes to multiple nodes, or
49 // removing some (redundant) nodes.
50 // During this phase, use the {RepresentationChanger} to insert
51 // representation changes between uses that demand a particular
52 // representation and nodes that produce a different representation.
53 LOWER
54};
55
56
57class RepresentationSelector {
58 public:
59 // Information for each node tracked during the fixpoint.
60 struct NodeInfo {
61 MachineTypeUnion use : 15; // Union of all usages for the node.
62 bool queued : 1; // Bookkeeping for the traversal.
63 bool visited : 1; // Bookkeeping for the traversal.
64 MachineTypeUnion output : 15; // Output type of the node.
65 };
66
67 RepresentationSelector(JSGraph* jsgraph, Zone* zone,
68 RepresentationChanger* changer)
69 : jsgraph_(jsgraph),
70 count_(jsgraph->graph()->NodeCount()),
71 info_(zone->NewArray<NodeInfo>(count_)),
72 nodes_(zone),
73 replacements_(zone),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 phase_(PROPAGATE),
75 changer_(changer),
76 queue_(zone) {
77 memset(info_, 0, sizeof(NodeInfo) * count_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078
79 Factory* f = zone->isolate()->factory();
80 safe_bit_range_ =
81 Type::Union(Type::Boolean(),
82 Type::Range(f->NewNumber(0), f->NewNumber(1), zone), zone);
83 safe_int_additive_range_ =
84 Type::Range(f->NewNumber(-std::pow(2.0, 52.0)),
85 f->NewNumber(std::pow(2.0, 52.0)), zone);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 }
87
88 void Run(SimplifiedLowering* lowering) {
89 // Run propagation phase to a fixpoint.
90 TRACE(("--{Propagation phase}--\n"));
91 phase_ = PROPAGATE;
92 Enqueue(jsgraph_->graph()->end());
93 // Process nodes from the queue until it is empty.
94 while (!queue_.empty()) {
95 Node* node = queue_.front();
96 NodeInfo* info = GetInfo(node);
97 queue_.pop();
98 info->queued = false;
99 TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
100 VisitNode(node, info->use, NULL);
101 TRACE((" ==> output "));
102 PrintInfo(info->output);
103 TRACE(("\n"));
104 }
105
106 // Run lowering and change insertion phase.
107 TRACE(("--{Simplified lowering phase}--\n"));
108 phase_ = LOWER;
109 // Process nodes from the collected {nodes_} vector.
110 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
111 Node* node = *i;
112 TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
113 // Reuse {VisitNode()} so the representation rules are in one place.
114 VisitNode(node, GetUseInfo(node), lowering);
115 }
116
117 // Perform the final replacements.
118 for (NodeVector::iterator i = replacements_.begin();
119 i != replacements_.end(); ++i) {
120 Node* node = *i;
121 Node* replacement = *(++i);
122 node->ReplaceUses(replacement);
123 }
124 }
125
126 // Enqueue {node} if the {use} contains new information for that node.
127 // Add {node} to {nodes_} if this is the first time it's been visited.
128 void Enqueue(Node* node, MachineTypeUnion use = 0) {
129 if (phase_ != PROPAGATE) return;
130 NodeInfo* info = GetInfo(node);
131 if (!info->visited) {
132 // First visit of this node.
133 info->visited = true;
134 info->queued = true;
135 nodes_.push_back(node);
136 queue_.push(node);
137 TRACE((" initial: "));
138 info->use |= use;
139 PrintUseInfo(node);
140 return;
141 }
142 TRACE((" queue?: "));
143 PrintUseInfo(node);
144 if ((info->use & use) != use) {
145 // New usage information for the node is available.
146 if (!info->queued) {
147 queue_.push(node);
148 info->queued = true;
149 TRACE((" added: "));
150 } else {
151 TRACE((" inqueue: "));
152 }
153 info->use |= use;
154 PrintUseInfo(node);
155 }
156 }
157
158 bool lower() { return phase_ == LOWER; }
159
160 void Enqueue(Node* node, MachineType use) {
161 Enqueue(node, static_cast<MachineTypeUnion>(use));
162 }
163
164 void SetOutput(Node* node, MachineTypeUnion output) {
165 // Every node should have at most one output representation. Note that
166 // phis can have 0, if they have not been used in a representation-inducing
167 // instruction.
168 DCHECK((output & kRepMask) == 0 ||
169 base::bits::IsPowerOfTwo32(output & kRepMask));
170 GetInfo(node)->output = output;
171 }
172
173 bool BothInputsAre(Node* node, Type* type) {
174 DCHECK_EQ(2, node->InputCount());
175 return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) &&
176 NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
177 }
178
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400179 void ProcessTruncateWord32Input(Node* node, int index, MachineTypeUnion use) {
180 Node* input = node->InputAt(index);
181 if (phase_ == PROPAGATE) {
182 // In the propagate phase, propagate the usage information backward.
183 Enqueue(input, use);
184 } else {
185 // In the change phase, insert a change before the use if necessary.
186 MachineTypeUnion output = GetInfo(input)->output;
187 if ((output & (kRepBit | kRepWord8 | kRepWord16 | kRepWord32)) == 0) {
188 // Output representation doesn't match usage.
189 TRACE((" truncate-to-int32: #%d:%s(@%d #%d:%s) ", node->id(),
190 node->op()->mnemonic(), index, input->id(),
191 input->op()->mnemonic()));
192 TRACE((" from "));
193 PrintInfo(output);
194 TRACE((" to "));
195 PrintInfo(use);
196 TRACE(("\n"));
197 Node* n = changer_->GetTruncatedWord32For(input, output);
198 node->ReplaceInput(index, n);
199 }
200 }
201 }
202
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 void ProcessInput(Node* node, int index, MachineTypeUnion use) {
204 Node* input = node->InputAt(index);
205 if (phase_ == PROPAGATE) {
206 // In the propagate phase, propagate the usage information backward.
207 Enqueue(input, use);
208 } else {
209 // In the change phase, insert a change before the use if necessary.
210 if ((use & kRepMask) == 0) return; // No input requirement on the use.
211 MachineTypeUnion output = GetInfo(input)->output;
212 if ((output & kRepMask & use) == 0) {
213 // Output representation doesn't match usage.
214 TRACE((" change: #%d:%s(@%d #%d:%s) ", node->id(),
215 node->op()->mnemonic(), index, input->id(),
216 input->op()->mnemonic()));
217 TRACE((" from "));
218 PrintInfo(output);
219 TRACE((" to "));
220 PrintInfo(use);
221 TRACE(("\n"));
222 Node* n = changer_->GetRepresentationFor(input, output, use);
223 node->ReplaceInput(index, n);
224 }
225 }
226 }
227
228 void ProcessRemainingInputs(Node* node, int index) {
229 DCHECK_GE(index, NodeProperties::PastValueIndex(node));
230 DCHECK_GE(index, NodeProperties::PastContextIndex(node));
231 for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
232 i < NodeProperties::PastEffectIndex(node); ++i) {
233 Enqueue(node->InputAt(i)); // Effect inputs: just visit
234 }
235 for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
236 i < NodeProperties::PastControlIndex(node); ++i) {
237 Enqueue(node->InputAt(i)); // Control inputs: just visit
238 }
239 }
240
241 // The default, most general visitation case. For {node}, process all value,
242 // context, effect, and control inputs, assuming that value inputs should have
243 // {kRepTagged} representation and can observe all output values {kTypeAny}.
244 void VisitInputs(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245 auto i = node->input_edges().begin();
246 for (int j = node->op()->ValueInputCount(); j > 0; ++i, j--) {
247 ProcessInput(node, (*i).index(), kMachAnyTagged); // Value inputs
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 }
249 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
250 ++i, j--) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400251 ProcessInput(node, (*i).index(), kMachAnyTagged); // Context inputs
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400253 for (int j = node->op()->EffectInputCount(); j > 0; ++i, j--) {
254 Enqueue((*i).to()); // Effect inputs: just visit
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256 for (int j = node->op()->ControlInputCount(); j > 0; ++i, j--) {
257 Enqueue((*i).to()); // Control inputs: just visit
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258 }
259 SetOutput(node, kMachAnyTagged);
260 }
261
262 // Helper for binops of the I x I -> O variety.
263 void VisitBinop(Node* node, MachineTypeUnion input_use,
264 MachineTypeUnion output) {
265 DCHECK_EQ(2, node->InputCount());
266 ProcessInput(node, 0, input_use);
267 ProcessInput(node, 1, input_use);
268 SetOutput(node, output);
269 }
270
271 // Helper for unops of the I -> O variety.
272 void VisitUnop(Node* node, MachineTypeUnion input_use,
273 MachineTypeUnion output) {
274 DCHECK_EQ(1, node->InputCount());
275 ProcessInput(node, 0, input_use);
276 SetOutput(node, output);
277 }
278
279 // Helper for leaf nodes.
280 void VisitLeaf(Node* node, MachineTypeUnion output) {
281 DCHECK_EQ(0, node->InputCount());
282 SetOutput(node, output);
283 }
284
285 // Helpers for specific types of binops.
286 void VisitFloat64Binop(Node* node) {
287 VisitBinop(node, kMachFloat64, kMachFloat64);
288 }
289 void VisitInt32Binop(Node* node) { VisitBinop(node, kMachInt32, kMachInt32); }
290 void VisitUint32Binop(Node* node) {
291 VisitBinop(node, kMachUint32, kMachUint32);
292 }
293 void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
294 void VisitUint64Binop(Node* node) {
295 VisitBinop(node, kMachUint64, kMachUint64);
296 }
297 void VisitFloat64Cmp(Node* node) { VisitBinop(node, kMachFloat64, kRepBit); }
298 void VisitInt32Cmp(Node* node) { VisitBinop(node, kMachInt32, kRepBit); }
299 void VisitUint32Cmp(Node* node) { VisitBinop(node, kMachUint32, kRepBit); }
300 void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
301 void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
302
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400303 // Infer representation for phi-like nodes.
304 MachineType GetRepresentationForPhi(Node* node, MachineTypeUnion use) {
305 // Phis adapt to the output representation their uses demand.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 Type* upper = NodeProperties::GetBounds(node).upper;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307 if ((use & kRepMask) == kRepTagged) {
308 // only tagged uses.
309 return kRepTagged;
310 } else if (upper->Is(Type::Integral32())) {
311 // Integer within [-2^31, 2^32[ range.
312 if ((use & kRepMask) == kRepFloat64) {
313 // only float64 uses.
314 return kRepFloat64;
315 } else if (upper->Is(Type::Signed32()) || upper->Is(Type::Unsigned32())) {
316 // multiple uses, but we are within 32 bits range => pick kRepWord32.
317 return kRepWord32;
318 } else if ((use & kRepMask) == kRepWord32 ||
319 (use & kTypeMask) == kTypeInt32 ||
320 (use & kTypeMask) == kTypeUint32) {
321 // We only use 32 bits or we use the result consistently.
322 return kRepWord32;
323 } else {
324 return kRepFloat64;
325 }
326 } else if (IsSafeBitOperand(node)) {
327 // multiple uses => pick kRepBit.
328 return kRepBit;
329 } else if (upper->Is(Type::Number())) {
330 // multiple uses => pick kRepFloat64.
331 return kRepFloat64;
332 }
333 return kRepTagged;
334 }
335
336 // Helper for handling selects.
337 void VisitSelect(Node* node, MachineTypeUnion use,
338 SimplifiedLowering* lowering) {
339 ProcessInput(node, 0, kRepBit);
340 MachineType output = GetRepresentationForPhi(node, use);
341
342 Type* upper = NodeProperties::GetBounds(node).upper;
343 MachineType output_type =
344 static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 SetOutput(node, output_type);
346
347 if (lower()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400348 // Update the select operator.
349 SelectParameters p = SelectParametersOf(node->op());
350 MachineType type = static_cast<MachineType>(output_type);
351 if (type != p.type()) {
352 node->set_op(lowering->common()->Select(type, p.hint()));
353 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000354
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400355 // Convert inputs to the output representation of this select.
356 ProcessInput(node, 1, output_type);
357 ProcessInput(node, 2, output_type);
358 } else {
359 // Propagate {use} of the select to value inputs.
360 MachineType use_type =
361 static_cast<MachineType>((use & kTypeMask) | output);
362 ProcessInput(node, 1, use_type);
363 ProcessInput(node, 2, use_type);
364 }
365 }
366
367 // Helper for handling phis.
368 void VisitPhi(Node* node, MachineTypeUnion use,
369 SimplifiedLowering* lowering) {
370 MachineType output = GetRepresentationForPhi(node, use);
371
372 Type* upper = NodeProperties::GetBounds(node).upper;
373 MachineType output_type =
374 static_cast<MachineType>(changer_->TypeFromUpperBound(upper) | output);
375 SetOutput(node, output_type);
376
377 int values = node->op()->ValueInputCount();
378
379 if (lower()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 // Update the phi operator.
381 MachineType type = static_cast<MachineType>(output_type);
382 if (type != OpParameter<MachineType>(node)) {
383 node->set_op(lowering->common()->Phi(type, values));
384 }
385
386 // Convert inputs to the output representation of this phi.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400387 for (Edge const edge : node->input_edges()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388 // TODO(titzer): it'd be nice to have distinguished edge kinds here.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400389 ProcessInput(node, edge.index(), values > 0 ? output_type : 0);
390 values--;
391 }
392 } else {
393 // Propagate {use} of the phi to value inputs, and 0 to control.
394 MachineType use_type =
395 static_cast<MachineType>((use & kTypeMask) | output);
396 for (Edge const edge : node->input_edges()) {
397 // TODO(titzer): it'd be nice to have distinguished edge kinds here.
398 ProcessInput(node, edge.index(), values > 0 ? use_type : 0);
399 values--;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000400 }
401 }
402 }
403
404 const Operator* Int32Op(Node* node) {
405 return changer_->Int32OperatorFor(node->opcode());
406 }
407
408 const Operator* Uint32Op(Node* node) {
409 return changer_->Uint32OperatorFor(node->opcode());
410 }
411
412 const Operator* Float64Op(Node* node) {
413 return changer_->Float64OperatorFor(node->opcode());
414 }
415
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400416 bool CanLowerToInt32Binop(Node* node, MachineTypeUnion use) {
417 return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use);
418 }
419
420 bool IsSafeBitOperand(Node* node) {
421 Type* type = NodeProperties::GetBounds(node).upper;
422 return type->Is(safe_bit_range_);
423 }
424
425 bool IsSafeIntAdditiveOperand(Node* node) {
426 Type* type = NodeProperties::GetBounds(node).upper;
427 // TODO(jarin): Unfortunately, bitset types are not subtypes of larger
428 // range types, so we have to explicitly check for Integral32 here
429 // (in addition to the safe integer range). Once we fix subtyping for
430 // ranges, we should simplify this.
431 return type->Is(safe_int_additive_range_) || type->Is(Type::Integral32());
432 }
433
434 bool CanLowerToInt32AdditiveBinop(Node* node, MachineTypeUnion use) {
435 return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
436 IsSafeIntAdditiveOperand(node->InputAt(1)) &&
437 !CanObserveNonInt32(use);
438 }
439
440 bool CanLowerToUint32Binop(Node* node, MachineTypeUnion use) {
441 return BothInputsAre(node, Type::Unsigned32()) && !CanObserveNonUint32(use);
442 }
443
444 bool CanLowerToUint32AdditiveBinop(Node* node, MachineTypeUnion use) {
445 return IsSafeIntAdditiveOperand(node->InputAt(0)) &&
446 IsSafeIntAdditiveOperand(node->InputAt(1)) &&
447 !CanObserveNonUint32(use);
448 }
449
450 bool CanObserveNonInt32(MachineTypeUnion use) {
451 return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
452 }
453
454 bool CanObserveMinusZero(MachineTypeUnion use) {
455 // TODO(turbofan): technically Uint32 cannot observe minus zero either.
456 return (use & (kTypeUint32 | kTypeNumber | kTypeAny)) != 0;
457 }
458
459 bool CanObserveNaN(MachineTypeUnion use) {
460 return (use & (kTypeNumber | kTypeAny)) != 0;
461 }
462
463 bool CanObserveNonUint32(MachineTypeUnion use) {
464 return (use & (kTypeInt32 | kTypeNumber | kTypeAny)) != 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 }
466
467 // Dispatching routine for visiting the node {node} with the usage {use}.
468 // Depending on the operator, propagate new usage info to the inputs.
469 void VisitNode(Node* node, MachineTypeUnion use,
470 SimplifiedLowering* lowering) {
471 switch (node->opcode()) {
472 //------------------------------------------------------------------
473 // Common operators.
474 //------------------------------------------------------------------
475 case IrOpcode::kStart:
476 case IrOpcode::kDead:
477 return VisitLeaf(node, 0);
478 case IrOpcode::kParameter: {
479 // TODO(titzer): use representation from linkage.
480 Type* upper = NodeProperties::GetBounds(node).upper;
481 ProcessInput(node, 0, 0);
482 SetOutput(node, kRepTagged | changer_->TypeFromUpperBound(upper));
483 return;
484 }
485 case IrOpcode::kInt32Constant:
486 return VisitLeaf(node, kRepWord32);
487 case IrOpcode::kInt64Constant:
488 return VisitLeaf(node, kRepWord64);
489 case IrOpcode::kFloat64Constant:
490 return VisitLeaf(node, kRepFloat64);
491 case IrOpcode::kExternalConstant:
492 return VisitLeaf(node, kMachPtr);
493 case IrOpcode::kNumberConstant:
494 return VisitLeaf(node, kRepTagged);
495 case IrOpcode::kHeapConstant:
496 return VisitLeaf(node, kRepTagged);
497
498 case IrOpcode::kEnd:
499 case IrOpcode::kIfTrue:
500 case IrOpcode::kIfFalse:
501 case IrOpcode::kReturn:
502 case IrOpcode::kMerge:
503 case IrOpcode::kThrow:
504 return VisitInputs(node); // default visit for all node inputs.
505
506 case IrOpcode::kBranch:
507 ProcessInput(node, 0, kRepBit);
508 Enqueue(NodeProperties::GetControlInput(node, 0));
509 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400510 case IrOpcode::kSelect:
511 return VisitSelect(node, use, lowering);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512 case IrOpcode::kPhi:
513 return VisitPhi(node, use, lowering);
514
515//------------------------------------------------------------------
516// JavaScript operators.
517//------------------------------------------------------------------
518// For now, we assume that all JS operators were too complex to lower
519// to Simplified and that they will always require tagged value inputs
520// and produce tagged value outputs.
521// TODO(turbofan): it might be possible to lower some JSOperators here,
522// but that responsibility really lies in the typed lowering phase.
523#define DEFINE_JS_CASE(x) case IrOpcode::k##x:
524 JS_OP_LIST(DEFINE_JS_CASE)
525#undef DEFINE_JS_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000526 VisitInputs(node);
527 return SetOutput(node, kRepTagged);
528
529 //------------------------------------------------------------------
530 // Simplified operators.
531 //------------------------------------------------------------------
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400532 case IrOpcode::kAnyToBoolean: {
533 if (IsSafeBitOperand(node->InputAt(0))) {
534 VisitUnop(node, kRepBit, kRepBit);
535 if (lower()) DeferReplacement(node, node->InputAt(0));
536 } else {
537 VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged);
538 if (lower()) {
539 // AnyToBoolean(x) => Call(ToBooleanStub, x, no-context)
540 Operator::Properties properties = node->op()->properties();
541 Callable callable = CodeFactory::ToBoolean(
542 jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL);
543 CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite;
544 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
545 callable.descriptor(), 0, flags, properties, jsgraph_->zone());
546 node->set_op(jsgraph_->common()->Call(desc));
547 node->InsertInput(jsgraph_->zone(), 0,
548 jsgraph_->HeapConstant(callable.code()));
549 node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
550 }
551 }
552 break;
553 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 case IrOpcode::kBooleanNot: {
555 if (lower()) {
556 MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
557 if (input & kRepBit) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400558 // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
559 node->set_op(lowering->machine()->Word32Equal());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
561 } else {
562 // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
563 node->set_op(lowering->machine()->WordEqual());
564 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
565 }
566 } else {
567 // No input representation requirement; adapt during lowering.
568 ProcessInput(node, 0, kTypeBool);
569 SetOutput(node, kRepBit);
570 }
571 break;
572 }
573 case IrOpcode::kBooleanToNumber: {
574 if (lower()) {
575 MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
576 if (input & kRepBit) {
577 // BooleanToNumber(x: kRepBit) => x
578 DeferReplacement(node, node->InputAt(0));
579 } else {
580 // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true)
581 node->set_op(lowering->machine()->WordEqual());
582 node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant());
583 }
584 } else {
585 // No input representation requirement; adapt during lowering.
586 ProcessInput(node, 0, kTypeBool);
587 SetOutput(node, kMachInt32);
588 }
589 break;
590 }
591 case IrOpcode::kNumberEqual:
592 case IrOpcode::kNumberLessThan:
593 case IrOpcode::kNumberLessThanOrEqual: {
594 // Number comparisons reduce to integer comparisons for integer inputs.
595 if (BothInputsAre(node, Type::Signed32())) {
596 // => signed Int32Cmp
597 VisitInt32Cmp(node);
598 if (lower()) node->set_op(Int32Op(node));
599 } else if (BothInputsAre(node, Type::Unsigned32())) {
600 // => unsigned Int32Cmp
601 VisitUint32Cmp(node);
602 if (lower()) node->set_op(Uint32Op(node));
603 } else {
604 // => Float64Cmp
605 VisitFloat64Cmp(node);
606 if (lower()) node->set_op(Float64Op(node));
607 }
608 break;
609 }
610 case IrOpcode::kNumberAdd:
611 case IrOpcode::kNumberSubtract: {
612 // Add and subtract reduce to Int32Add/Sub if the inputs
613 // are already integers and all uses are truncating.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400614 if (CanLowerToInt32Binop(node, use)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000615 // => signed Int32Add/Sub
616 VisitInt32Binop(node);
617 if (lower()) node->set_op(Int32Op(node));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400618 } else if (CanLowerToInt32AdditiveBinop(node, use)) {
619 // => signed Int32Add/Sub, truncating inputs
620 ProcessTruncateWord32Input(node, 0, kTypeInt32);
621 ProcessTruncateWord32Input(node, 1, kTypeInt32);
622 SetOutput(node, kMachInt32);
623 if (lower()) node->set_op(Int32Op(node));
624 } else if (CanLowerToUint32Binop(node, use)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625 // => unsigned Int32Add/Sub
626 VisitUint32Binop(node);
627 if (lower()) node->set_op(Uint32Op(node));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400628 } else if (CanLowerToUint32AdditiveBinop(node, use)) {
629 // => signed Int32Add/Sub, truncating inputs
630 ProcessTruncateWord32Input(node, 0, kTypeUint32);
631 ProcessTruncateWord32Input(node, 1, kTypeUint32);
632 SetOutput(node, kMachUint32);
633 if (lower()) node->set_op(Uint32Op(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 } else {
635 // => Float64Add/Sub
636 VisitFloat64Binop(node);
637 if (lower()) node->set_op(Float64Op(node));
638 }
639 break;
640 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400641 case IrOpcode::kNumberMultiply: {
642 NumberMatcher right(node->InputAt(1));
643 if (right.IsInRange(-1048576, 1048576)) { // must fit double mantissa.
644 if (CanLowerToInt32Binop(node, use)) {
645 // => signed Int32Mul
646 VisitInt32Binop(node);
647 if (lower()) node->set_op(Int32Op(node));
648 break;
649 }
650 }
651 // => Float64Mul
652 VisitFloat64Binop(node);
653 if (lower()) node->set_op(Float64Op(node));
654 break;
655 }
656 case IrOpcode::kNumberDivide: {
657 if (CanLowerToInt32Binop(node, use)) {
658 // => signed Int32Div
659 VisitInt32Binop(node);
660 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
661 break;
662 }
663 if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
664 // => unsigned Uint32Div
665 VisitUint32Binop(node);
666 if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
667 break;
668 }
669 // => Float64Div
670 VisitFloat64Binop(node);
671 if (lower()) node->set_op(Float64Op(node));
672 break;
673 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 case IrOpcode::kNumberModulus: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400675 if (CanLowerToInt32Binop(node, use)) {
676 // => signed Int32Mod
677 VisitInt32Binop(node);
678 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
679 break;
680 }
681 if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
682 // => unsigned Uint32Mod
683 VisitUint32Binop(node);
684 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
685 break;
686 }
687 // => Float64Mod
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688 VisitFloat64Binop(node);
689 if (lower()) node->set_op(Float64Op(node));
690 break;
691 }
692 case IrOpcode::kNumberToInt32: {
693 MachineTypeUnion use_rep = use & kRepMask;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400694 Node* input = node->InputAt(0);
695 Type* in_upper = NodeProperties::GetBounds(input).upper;
696 MachineTypeUnion in = GetInfo(input)->output;
697 if (in_upper->Is(Type::Signed32())) {
698 // If the input has type int32, pass through representation.
699 VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
700 if (lower()) DeferReplacement(node, node->InputAt(0));
701 } else if ((in & kTypeMask) == kTypeUint32 ||
702 in_upper->Is(Type::Unsigned32())) {
703 // Just change representation if necessary.
704 VisitUnop(node, kTypeUint32 | kRepWord32, kTypeInt32 | kRepWord32);
705 if (lower()) DeferReplacement(node, node->InputAt(0));
706 } else if ((in & kTypeMask) == kTypeInt32 ||
707 (in & kRepMask) == kRepWord32) {
708 // Just change representation if necessary.
709 VisitUnop(node, kTypeInt32 | kRepWord32, kTypeInt32 | kRepWord32);
710 if (lower()) DeferReplacement(node, node->InputAt(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400712 // Require the input in float64 format and perform truncation.
713 // TODO(turbofan): avoid a truncation with a smi check.
714 VisitUnop(node, kTypeInt32 | kRepFloat64, kTypeInt32 | kRepWord32);
715 if (lower())
716 node->set_op(lowering->machine()->TruncateFloat64ToInt32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000717 }
718 break;
719 }
720 case IrOpcode::kNumberToUint32: {
721 MachineTypeUnion use_rep = use & kRepMask;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400722 Node* input = node->InputAt(0);
723 Type* in_upper = NodeProperties::GetBounds(input).upper;
724 MachineTypeUnion in = GetInfo(input)->output;
725 if (in_upper->Is(Type::Unsigned32())) {
726 // If the input has type uint32, pass through representation.
727 VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
728 if (lower()) DeferReplacement(node, node->InputAt(0));
729 } else if ((in & kTypeMask) == kTypeUint32 ||
730 in_upper->Is(Type::Unsigned32())) {
731 // Just change representation if necessary.
732 VisitUnop(node, kTypeUint32 | kRepWord32, kTypeUint32 | kRepWord32);
733 if (lower()) DeferReplacement(node, node->InputAt(0));
734 } else if ((in & kTypeMask) == kTypeInt32 ||
735 (in & kRepMask) == kRepWord32) {
736 // Just change representation if necessary.
737 VisitUnop(node, kTypeInt32 | kRepWord32, kTypeUint32 | kRepWord32);
738 if (lower()) DeferReplacement(node, node->InputAt(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000739 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400740 // Require the input in float64 format and perform truncation.
741 // TODO(turbofan): avoid a truncation with a smi check.
742 VisitUnop(node, kTypeUint32 | kRepFloat64, kTypeUint32 | kRepWord32);
743 if (lower())
744 node->set_op(lowering->machine()->TruncateFloat64ToInt32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745 }
746 break;
747 }
748 case IrOpcode::kReferenceEqual: {
749 VisitBinop(node, kMachAnyTagged, kRepBit);
750 if (lower()) node->set_op(lowering->machine()->WordEqual());
751 break;
752 }
753 case IrOpcode::kStringEqual: {
754 VisitBinop(node, kMachAnyTagged, kRepBit);
755 if (lower()) lowering->DoStringEqual(node);
756 break;
757 }
758 case IrOpcode::kStringLessThan: {
759 VisitBinop(node, kMachAnyTagged, kRepBit);
760 if (lower()) lowering->DoStringLessThan(node);
761 break;
762 }
763 case IrOpcode::kStringLessThanOrEqual: {
764 VisitBinop(node, kMachAnyTagged, kRepBit);
765 if (lower()) lowering->DoStringLessThanOrEqual(node);
766 break;
767 }
768 case IrOpcode::kStringAdd: {
769 VisitBinop(node, kMachAnyTagged, kMachAnyTagged);
770 if (lower()) lowering->DoStringAdd(node);
771 break;
772 }
773 case IrOpcode::kLoadField: {
774 FieldAccess access = FieldAccessOf(node->op());
775 ProcessInput(node, 0, changer_->TypeForBasePointer(access));
776 ProcessRemainingInputs(node, 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400777 SetOutput(node, access.machine_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000778 if (lower()) lowering->DoLoadField(node);
779 break;
780 }
781 case IrOpcode::kStoreField: {
782 FieldAccess access = FieldAccessOf(node->op());
783 ProcessInput(node, 0, changer_->TypeForBasePointer(access));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400784 ProcessInput(node, 1, access.machine_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785 ProcessRemainingInputs(node, 2);
786 SetOutput(node, 0);
787 if (lower()) lowering->DoStoreField(node);
788 break;
789 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400790 case IrOpcode::kLoadBuffer: {
791 BufferAccess access = BufferAccessOf(node->op());
792 ProcessInput(node, 0, kMachPtr); // buffer
793 ProcessInput(node, 1, kMachInt32); // offset
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794 ProcessInput(node, 2, kMachInt32); // length
795 ProcessRemainingInputs(node, 3);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400796 // Tagged overrides everything if we have to do a typed array bounds
797 // check, because we may need to return undefined then.
798 MachineType output_type;
799 if (use & kRepTagged) {
800 output_type = kMachAnyTagged;
801 } else if (use & kRepFloat64) {
802 if (access.machine_type() & kRepFloat32) {
803 output_type = access.machine_type();
804 } else {
805 output_type = kMachFloat64;
806 }
807 } else if (use & kRepFloat32) {
808 output_type = kMachFloat32;
809 } else {
810 output_type = access.machine_type();
811 }
812 SetOutput(node, output_type);
813 if (lower()) lowering->DoLoadBuffer(node, output_type, changer_);
814 break;
815 }
816 case IrOpcode::kStoreBuffer: {
817 BufferAccess access = BufferAccessOf(node->op());
818 ProcessInput(node, 0, kMachPtr); // buffer
819 ProcessInput(node, 1, kMachInt32); // offset
820 ProcessInput(node, 2, kMachInt32); // length
821 ProcessInput(node, 3, access.machine_type()); // value
822 ProcessRemainingInputs(node, 4);
823 SetOutput(node, 0);
824 if (lower()) lowering->DoStoreBuffer(node);
825 break;
826 }
827 case IrOpcode::kLoadElement: {
828 ElementAccess access = ElementAccessOf(node->op());
829 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base
830 ProcessInput(node, 1, kMachInt32); // index
831 ProcessRemainingInputs(node, 2);
832 SetOutput(node, access.machine_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833 if (lower()) lowering->DoLoadElement(node);
834 break;
835 }
836 case IrOpcode::kStoreElement: {
837 ElementAccess access = ElementAccessOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400838 ProcessInput(node, 0, changer_->TypeForBasePointer(access)); // base
839 ProcessInput(node, 1, kMachInt32); // index
840 ProcessInput(node, 2, access.machine_type); // value
841 ProcessRemainingInputs(node, 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 SetOutput(node, 0);
843 if (lower()) lowering->DoStoreElement(node);
844 break;
845 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400846 case IrOpcode::kObjectIsSmi: {
847 ProcessInput(node, 0, kMachAnyTagged);
848 SetOutput(node, kRepBit | kTypeBool);
849 if (lower()) {
850 Node* is_tagged = jsgraph_->graph()->NewNode(
851 jsgraph_->machine()->WordAnd(), node->InputAt(0),
852 jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
853 Node* is_smi = jsgraph_->graph()->NewNode(
854 jsgraph_->machine()->WordEqual(), is_tagged,
855 jsgraph_->Int32Constant(kSmiTag));
856 DeferReplacement(node, is_smi);
857 }
858 break;
859 }
860 case IrOpcode::kObjectIsNonNegativeSmi: {
861 ProcessInput(node, 0, kMachAnyTagged);
862 SetOutput(node, kRepBit | kTypeBool);
863 if (lower()) {
864 Node* is_tagged = jsgraph_->graph()->NewNode(
865 jsgraph_->machine()->WordAnd(), node->InputAt(0),
866 jsgraph_->Int32Constant(static_cast<int>(kSmiTagMask)));
867 Node* is_smi = jsgraph_->graph()->NewNode(
868 jsgraph_->machine()->WordEqual(), is_tagged,
869 jsgraph_->Int32Constant(kSmiTag));
870 Node* is_non_neg = jsgraph_->graph()->NewNode(
871 jsgraph_->machine()->IntLessThanOrEqual(),
872 jsgraph_->Int32Constant(0), node->InputAt(0));
873 Node* is_non_neg_smi = jsgraph_->graph()->NewNode(
874 jsgraph_->machine()->Word32And(), is_smi, is_non_neg);
875 DeferReplacement(node, is_non_neg_smi);
876 }
877 break;
878 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000879
880 //------------------------------------------------------------------
881 // Machine-level operators.
882 //------------------------------------------------------------------
883 case IrOpcode::kLoad: {
884 // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400885 MachineTypeUnion tBase = kRepTagged | kMachPtr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000886 LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
887 ProcessInput(node, 0, tBase); // pointer or object
888 ProcessInput(node, 1, kMachInt32); // index
889 ProcessRemainingInputs(node, 2);
890 SetOutput(node, rep);
891 break;
892 }
893 case IrOpcode::kStore: {
894 // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400895 MachineTypeUnion tBase = kRepTagged | kMachPtr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000896 StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
897 ProcessInput(node, 0, tBase); // pointer or object
898 ProcessInput(node, 1, kMachInt32); // index
899 ProcessInput(node, 2, rep.machine_type());
900 ProcessRemainingInputs(node, 3);
901 SetOutput(node, 0);
902 break;
903 }
904 case IrOpcode::kWord32Shr:
905 // We output unsigned int32 for shift right because JavaScript.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400906 return VisitBinop(node, kMachUint32, kMachUint32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000907 case IrOpcode::kWord32And:
908 case IrOpcode::kWord32Or:
909 case IrOpcode::kWord32Xor:
910 case IrOpcode::kWord32Shl:
911 case IrOpcode::kWord32Sar:
912 // We use signed int32 as the output type for these word32 operations,
913 // though the machine bits are the same for either signed or unsigned,
914 // because JavaScript considers the result from these operations signed.
915 return VisitBinop(node, kRepWord32, kRepWord32 | kTypeInt32);
916 case IrOpcode::kWord32Equal:
917 return VisitBinop(node, kRepWord32, kRepBit);
918
919 case IrOpcode::kInt32Add:
920 case IrOpcode::kInt32Sub:
921 case IrOpcode::kInt32Mul:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400922 case IrOpcode::kInt32MulHigh:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000923 case IrOpcode::kInt32Div:
924 case IrOpcode::kInt32Mod:
925 return VisitInt32Binop(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400926 case IrOpcode::kUint32Div:
927 case IrOpcode::kUint32Mod:
928 case IrOpcode::kUint32MulHigh:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000929 return VisitUint32Binop(node);
930 case IrOpcode::kInt32LessThan:
931 case IrOpcode::kInt32LessThanOrEqual:
932 return VisitInt32Cmp(node);
933
934 case IrOpcode::kUint32LessThan:
935 case IrOpcode::kUint32LessThanOrEqual:
936 return VisitUint32Cmp(node);
937
938 case IrOpcode::kInt64Add:
939 case IrOpcode::kInt64Sub:
940 case IrOpcode::kInt64Mul:
941 case IrOpcode::kInt64Div:
942 case IrOpcode::kInt64Mod:
943 return VisitInt64Binop(node);
944 case IrOpcode::kInt64LessThan:
945 case IrOpcode::kInt64LessThanOrEqual:
946 return VisitInt64Cmp(node);
947
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400948 case IrOpcode::kUint64LessThan:
949 return VisitUint64Cmp(node);
950
951 case IrOpcode::kUint64Div:
952 case IrOpcode::kUint64Mod:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953 return VisitUint64Binop(node);
954
955 case IrOpcode::kWord64And:
956 case IrOpcode::kWord64Or:
957 case IrOpcode::kWord64Xor:
958 case IrOpcode::kWord64Shl:
959 case IrOpcode::kWord64Shr:
960 case IrOpcode::kWord64Sar:
961 return VisitBinop(node, kRepWord64, kRepWord64);
962 case IrOpcode::kWord64Equal:
963 return VisitBinop(node, kRepWord64, kRepBit);
964
965 case IrOpcode::kChangeInt32ToInt64:
966 return VisitUnop(node, kTypeInt32 | kRepWord32,
967 kTypeInt32 | kRepWord64);
968 case IrOpcode::kChangeUint32ToUint64:
969 return VisitUnop(node, kTypeUint32 | kRepWord32,
970 kTypeUint32 | kRepWord64);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400971 case IrOpcode::kTruncateFloat64ToFloat32:
972 return VisitUnop(node, kTypeNumber | kRepFloat64,
973 kTypeNumber | kRepFloat32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974 case IrOpcode::kTruncateInt64ToInt32:
975 // TODO(titzer): Is kTypeInt32 correct here?
976 return VisitUnop(node, kTypeInt32 | kRepWord64,
977 kTypeInt32 | kRepWord32);
978
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400979 case IrOpcode::kChangeFloat32ToFloat64:
980 return VisitUnop(node, kTypeNumber | kRepFloat32,
981 kTypeNumber | kRepFloat64);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000982 case IrOpcode::kChangeInt32ToFloat64:
983 return VisitUnop(node, kTypeInt32 | kRepWord32,
984 kTypeInt32 | kRepFloat64);
985 case IrOpcode::kChangeUint32ToFloat64:
986 return VisitUnop(node, kTypeUint32 | kRepWord32,
987 kTypeUint32 | kRepFloat64);
988 case IrOpcode::kChangeFloat64ToInt32:
989 return VisitUnop(node, kTypeInt32 | kRepFloat64,
990 kTypeInt32 | kRepWord32);
991 case IrOpcode::kChangeFloat64ToUint32:
992 return VisitUnop(node, kTypeUint32 | kRepFloat64,
993 kTypeUint32 | kRepWord32);
994
995 case IrOpcode::kFloat64Add:
996 case IrOpcode::kFloat64Sub:
997 case IrOpcode::kFloat64Mul:
998 case IrOpcode::kFloat64Div:
999 case IrOpcode::kFloat64Mod:
1000 return VisitFloat64Binop(node);
1001 case IrOpcode::kFloat64Sqrt:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001002 case IrOpcode::kFloat64Floor:
1003 case IrOpcode::kFloat64Ceil:
1004 case IrOpcode::kFloat64RoundTruncate:
1005 case IrOpcode::kFloat64RoundTiesAway:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006 return VisitUnop(node, kMachFloat64, kMachFloat64);
1007 case IrOpcode::kFloat64Equal:
1008 case IrOpcode::kFloat64LessThan:
1009 case IrOpcode::kFloat64LessThanOrEqual:
1010 return VisitFloat64Cmp(node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001011 case IrOpcode::kLoadStackPointer:
1012 return VisitLeaf(node, kMachPtr);
1013 case IrOpcode::kStateValues:
1014 for (int i = 0; i < node->InputCount(); i++) {
1015 ProcessInput(node, i, kTypeAny);
1016 }
1017 SetOutput(node, kMachAnyTagged);
1018 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001019 default:
1020 VisitInputs(node);
1021 break;
1022 }
1023 }
1024
1025 void DeferReplacement(Node* node, Node* replacement) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001026 if (FLAG_trace_representation) {
1027 TRACE(("defer replacement #%d:%s with #%d:%s\n", node->id(),
1028 node->op()->mnemonic(), replacement->id(),
1029 replacement->op()->mnemonic()));
1030 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001031 if (replacement->id() < count_) {
1032 // Replace with a previously existing node eagerly.
1033 node->ReplaceUses(replacement);
1034 } else {
1035 // Otherwise, we are replacing a node with a representation change.
1036 // Such a substitution must be done after all lowering is done, because
1037 // new nodes do not have {NodeInfo} entries, and that would confuse
1038 // the representation change insertion for uses of it.
1039 replacements_.push_back(node);
1040 replacements_.push_back(replacement);
1041 }
1042 // TODO(titzer) node->RemoveAllInputs(); // Node is now dead.
1043 }
1044
1045 void PrintUseInfo(Node* node) {
1046 TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic()));
1047 PrintInfo(GetUseInfo(node));
1048 TRACE(("\n"));
1049 }
1050
1051 void PrintInfo(MachineTypeUnion info) {
1052 if (FLAG_trace_representation) {
1053 OFStream os(stdout);
1054 os << static_cast<MachineType>(info);
1055 }
1056 }
1057
1058 private:
1059 JSGraph* jsgraph_;
1060 int count_; // number of nodes in the graph
1061 NodeInfo* info_; // node id -> usage information
1062 NodeVector nodes_; // collected nodes
1063 NodeVector replacements_; // replacements to be done after lowering
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064 Phase phase_; // current phase of algorithm
1065 RepresentationChanger* changer_; // for inserting representation changes
1066 ZoneQueue<Node*> queue_; // queue for traversing the graph
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001067 Type* safe_bit_range_;
1068 Type* safe_int_additive_range_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001069
1070 NodeInfo* GetInfo(Node* node) {
1071 DCHECK(node->id() >= 0);
1072 DCHECK(node->id() < count_);
1073 return &info_[node->id()];
1074 }
1075
1076 MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
1077};
1078
1079
1080Node* SimplifiedLowering::IsTagged(Node* node) {
1081 // TODO(titzer): factor this out to a TaggingScheme abstraction.
1082 STATIC_ASSERT(kSmiTagMask == 1); // Only works if tag is the low bit.
1083 return graph()->NewNode(machine()->WordAnd(), node,
1084 jsgraph()->Int32Constant(kSmiTagMask));
1085}
1086
1087
1088void SimplifiedLowering::LowerAllNodes() {
1089 SimplifiedOperatorBuilder simplified(graph()->zone());
1090 RepresentationChanger changer(jsgraph(), &simplified,
1091 graph()->zone()->isolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001092 RepresentationSelector selector(jsgraph(), zone_, &changer);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 selector.Run(this);
1094}
1095
1096
1097Node* SimplifiedLowering::Untag(Node* node) {
1098 // TODO(titzer): factor this out to a TaggingScheme abstraction.
1099 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
1100 return graph()->NewNode(machine()->WordSar(), node, shift_amount);
1101}
1102
1103
1104Node* SimplifiedLowering::SmiTag(Node* node) {
1105 // TODO(titzer): factor this out to a TaggingScheme abstraction.
1106 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
1107 return graph()->NewNode(machine()->WordShl(), node, shift_amount);
1108}
1109
1110
1111Node* SimplifiedLowering::OffsetMinusTagConstant(int32_t offset) {
1112 return jsgraph()->Int32Constant(offset - kHeapObjectTag);
1113}
1114
1115
1116static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
1117 MachineType representation,
1118 Type* type) {
1119 // TODO(turbofan): skip write barriers for Smis, etc.
1120 if (base_is_tagged == kTaggedBase &&
1121 RepresentationOf(representation) == kRepTagged) {
1122 // Write barriers are only for writes into heap objects (i.e. tagged base).
1123 return kFullWriteBarrier;
1124 }
1125 return kNoWriteBarrier;
1126}
1127
1128
1129void SimplifiedLowering::DoLoadField(Node* node) {
1130 const FieldAccess& access = FieldAccessOf(node->op());
1131 node->set_op(machine()->Load(access.machine_type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001132 Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
1133 node->InsertInput(graph()->zone(), 1, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001134}
1135
1136
1137void SimplifiedLowering::DoStoreField(Node* node) {
1138 const FieldAccess& access = FieldAccessOf(node->op());
1139 WriteBarrierKind kind = ComputeWriteBarrierKind(
1140 access.base_is_tagged, access.machine_type, access.type);
1141 node->set_op(
1142 machine()->Store(StoreRepresentation(access.machine_type, kind)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001143 Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
1144 node->InsertInput(graph()->zone(), 1, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145}
1146
1147
1148Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001149 Node* const key) {
1150 Node* index = key;
1151 const int element_size_shift = ElementSizeLog2Of(access.machine_type);
1152 if (element_size_shift) {
1153 index = graph()->NewNode(machine()->Word32Shl(), index,
1154 jsgraph()->Int32Constant(element_size_shift));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001155 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001156 const int fixed_offset = access.header_size - access.tag();
1157 if (fixed_offset) {
1158 index = graph()->NewNode(machine()->Int32Add(), index,
1159 jsgraph()->Int32Constant(fixed_offset));
1160 }
1161 if (machine()->Is64()) {
1162 // TODO(turbofan): This is probably only correct for typed arrays, and only
1163 // if the typed arrays are at most 2GiB in size, which happens to match
1164 // exactly our current situation.
1165 index = graph()->NewNode(machine()->ChangeUint32ToUint64(), index);
1166 }
1167 return index;
1168}
1169
1170
1171void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type,
1172 RepresentationChanger* changer) {
1173 DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
1174 DCHECK_NE(kMachNone, RepresentationOf(output_type));
1175 MachineType const type = BufferAccessOf(node->op()).machine_type();
1176 if (output_type != type) {
1177 Node* const buffer = node->InputAt(0);
1178 Node* const offset = node->InputAt(1);
1179 Node* const length = node->InputAt(2);
1180 Node* const effect = node->InputAt(3);
1181 Node* const control = node->InputAt(4);
1182 Node* const index =
1183 machine()->Is64()
1184 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset)
1185 : offset;
1186
1187 Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
1188 Node* branch =
1189 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1190
1191 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1192 Node* etrue =
1193 graph()->NewNode(machine()->Load(type), buffer, index, effect, if_true);
1194 Node* vtrue = changer->GetRepresentationFor(etrue, type, output_type);
1195
1196 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1197 Node* efalse = effect;
1198 Node* vfalse;
1199 if (output_type & kRepTagged) {
1200 vfalse = jsgraph()->UndefinedConstant();
1201 } else if (output_type & kRepFloat64) {
1202 vfalse =
1203 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
1204 } else if (output_type & kRepFloat32) {
1205 vfalse =
1206 jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
1207 } else {
1208 vfalse = jsgraph()->Int32Constant(0);
1209 }
1210
1211 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
1212 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
1213
1214 // Replace effect uses of {node} with the {ephi}.
1215 NodeProperties::ReplaceWithValue(node, node, ephi);
1216
1217 // Turn the {node} into a Phi.
1218 node->set_op(common()->Phi(output_type, 2));
1219 node->ReplaceInput(0, vtrue);
1220 node->ReplaceInput(1, vfalse);
1221 node->ReplaceInput(2, merge);
1222 node->TrimInputCount(3);
1223 } else {
1224 node->set_op(machine()->CheckedLoad(type));
1225 }
1226}
1227
1228
1229void SimplifiedLowering::DoStoreBuffer(Node* node) {
1230 DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
1231 MachineType const type = BufferAccessOf(node->op()).machine_type();
1232 node->set_op(machine()->CheckedStore(type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001233}
1234
1235
1236void SimplifiedLowering::DoLoadElement(Node* node) {
1237 const ElementAccess& access = ElementAccessOf(node->op());
1238 node->set_op(machine()->Load(access.machine_type));
1239 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240}
1241
1242
1243void SimplifiedLowering::DoStoreElement(Node* node) {
1244 const ElementAccess& access = ElementAccessOf(node->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001245 node->set_op(machine()->Store(StoreRepresentation(
1246 access.machine_type,
1247 ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
1248 access.type))));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001250}
1251
1252
1253void SimplifiedLowering::DoStringAdd(Node* node) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001254 Operator::Properties properties = node->op()->properties();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 Callable callable = CodeFactory::StringAdd(
1256 zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
1257 CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001258 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1259 callable.descriptor(), 0, flags, properties, zone());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 node->set_op(common()->Call(desc));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001261 node->InsertInput(graph()->zone(), 0,
1262 jsgraph()->HeapConstant(callable.code()));
1263 node->AppendInput(graph()->zone(), jsgraph()->UndefinedConstant());
1264 node->AppendInput(graph()->zone(), graph()->start());
1265 node->AppendInput(graph()->zone(), graph()->start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001266}
1267
1268
1269Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
1270 CEntryStub stub(zone()->isolate(), 1);
1271 Runtime::FunctionId f =
1272 requires_ordering ? Runtime::kStringCompare : Runtime::kStringEquals;
1273 ExternalReference ref(f, zone()->isolate());
1274 Operator::Properties props = node->op()->properties();
1275 // TODO(mstarzinger): We should call StringCompareStub here instead, once an
1276 // interface descriptor is available for it.
1277 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(f, 2, props, zone());
1278 return graph()->NewNode(common()->Call(desc),
1279 jsgraph()->HeapConstant(stub.GetCode()),
1280 NodeProperties::GetValueInput(node, 0),
1281 NodeProperties::GetValueInput(node, 1),
1282 jsgraph()->ExternalConstant(ref),
1283 jsgraph()->Int32Constant(2),
1284 jsgraph()->UndefinedConstant());
1285}
1286
1287
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001288Node* SimplifiedLowering::Int32Div(Node* const node) {
1289 Int32BinopMatcher m(node);
1290 Node* const zero = jsgraph()->Int32Constant(0);
1291 Node* const lhs = m.left().node();
1292 Node* const rhs = m.right().node();
1293
1294 if (m.right().Is(-1)) {
1295 return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
1296 } else if (m.right().Is(0)) {
1297 return rhs;
1298 } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
1299 return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
1300 }
1301
1302 Diamond if_zero(graph(), common(),
1303 graph()->NewNode(machine()->Word32Equal(), rhs, zero),
1304 BranchHint::kFalse);
1305
1306 Diamond if_minus_one(graph(), common(),
1307 graph()->NewNode(machine()->Word32Equal(), rhs,
1308 jsgraph()->Int32Constant(-1)),
1309 BranchHint::kFalse);
1310 if_minus_one.Nest(if_zero, false);
1311 Node* sub = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
1312 Node* div =
1313 graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_minus_one.if_false);
1314
1315 return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
1316}
1317
1318
1319Node* SimplifiedLowering::Int32Mod(Node* const node) {
1320 Int32BinopMatcher m(node);
1321 Node* const zero = jsgraph()->Int32Constant(0);
1322 Node* const minus_one = jsgraph()->Int32Constant(-1);
1323 Node* const lhs = m.left().node();
1324 Node* const rhs = m.right().node();
1325
1326 if (m.right().Is(-1) || m.right().Is(0)) {
1327 return zero;
1328 } else if (m.right().HasValue()) {
1329 return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
1330 }
1331
1332 // General case for signed integer modulus, with optimization for (unknown)
1333 // power of 2 right hand side.
1334 //
1335 // if 0 < rhs then
1336 // msk = rhs - 1
1337 // if rhs & msk != 0 then
1338 // lhs % rhs
1339 // else
1340 // if lhs < 0 then
1341 // -(-lhs & msk)
1342 // else
1343 // lhs & msk
1344 // else
1345 // if rhs < -1 then
1346 // lhs % rhs
1347 // else
1348 // zero
1349 //
1350 // Note: We do not use the Diamond helper class here, because it really hurts
1351 // readability with nested diamonds.
1352 const Operator* const merge_op = common()->Merge(2);
1353 const Operator* const phi_op = common()->Phi(kMachInt32, 2);
1354
1355 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
1356 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
1357 graph()->start());
1358
1359 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1360 Node* true0;
1361 {
1362 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
1363
1364 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
1365 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
1366
1367 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1368 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
1369
1370 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1371 Node* false1;
1372 {
1373 Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
1374 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
1375 check2, if_false1);
1376
1377 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1378 Node* true2 = graph()->NewNode(
1379 machine()->Int32Sub(), zero,
1380 graph()->NewNode(machine()->Word32And(),
1381 graph()->NewNode(machine()->Int32Sub(), zero, lhs),
1382 msk));
1383
1384 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1385 Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
1386
1387 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
1388 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
1389 }
1390
1391 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
1392 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
1393 }
1394
1395 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1396 Node* false0;
1397 {
1398 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
1399 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
1400 check1, if_false0);
1401
1402 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1403 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
1404
1405 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1406 Node* false1 = zero;
1407
1408 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
1409 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
1410 }
1411
1412 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
1413 return graph()->NewNode(phi_op, true0, false0, merge0);
1414}
1415
1416
1417Node* SimplifiedLowering::Uint32Div(Node* const node) {
1418 Uint32BinopMatcher m(node);
1419 Node* const zero = jsgraph()->Uint32Constant(0);
1420 Node* const lhs = m.left().node();
1421 Node* const rhs = m.right().node();
1422
1423 if (m.right().Is(0)) {
1424 return zero;
1425 } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
1426 return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
1427 }
1428
1429 Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
1430 Diamond d(graph(), common(), check, BranchHint::kFalse);
1431 Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
1432 return d.Phi(kMachUint32, zero, div);
1433}
1434
1435
1436Node* SimplifiedLowering::Uint32Mod(Node* const node) {
1437 Uint32BinopMatcher m(node);
1438 Node* const minus_one = jsgraph()->Int32Constant(-1);
1439 Node* const zero = jsgraph()->Uint32Constant(0);
1440 Node* const lhs = m.left().node();
1441 Node* const rhs = m.right().node();
1442
1443 if (m.right().Is(0)) {
1444 return zero;
1445 } else if (m.right().HasValue()) {
1446 return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
1447 }
1448
1449 // General case for unsigned integer modulus, with optimization for (unknown)
1450 // power of 2 right hand side.
1451 //
1452 // if rhs then
1453 // msk = rhs - 1
1454 // if rhs & msk != 0 then
1455 // lhs % rhs
1456 // else
1457 // lhs & msk
1458 // else
1459 // zero
1460 //
1461 // Note: We do not use the Diamond helper class here, because it really hurts
1462 // readability with nested diamonds.
1463 const Operator* const merge_op = common()->Merge(2);
1464 const Operator* const phi_op = common()->Phi(kMachInt32, 2);
1465
1466 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
1467 graph()->start());
1468
1469 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1470 Node* true0;
1471 {
1472 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
1473
1474 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
1475 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
1476
1477 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1478 Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
1479
1480 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1481 Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
1482
1483 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
1484 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
1485 }
1486
1487 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1488 Node* false0 = zero;
1489
1490 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
1491 return graph()->NewNode(phi_op, true0, false0, merge0);
1492}
1493
1494
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001495void SimplifiedLowering::DoStringEqual(Node* node) {
1496 node->set_op(machine()->WordEqual());
1497 node->ReplaceInput(0, StringComparison(node, false));
1498 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
1499}
1500
1501
1502void SimplifiedLowering::DoStringLessThan(Node* node) {
1503 node->set_op(machine()->IntLessThan());
1504 node->ReplaceInput(0, StringComparison(node, true));
1505 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
1506}
1507
1508
1509void SimplifiedLowering::DoStringLessThanOrEqual(Node* node) {
1510 node->set_op(machine()->IntLessThanOrEqual());
1511 node->ReplaceInput(0, StringComparison(node, true));
1512 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
1513}
1514
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001515} // namespace compiler
1516} // namespace internal
1517} // namespace v8