1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/simplified-lowering.h"
6
7 #include <limits>
8
9 #include "src/address-map.h"
10 #include "src/base/bits.h"
11 #include "src/code-factory.h"
12 #include "src/compiler/access-builder.h"
13 #include "src/compiler/common-operator.h"
14 #include "src/compiler/compiler-source-position-table.h"
15 #include "src/compiler/diamond.h"
16 #include "src/compiler/linkage.h"
17 #include "src/compiler/node-matchers.h"
18 #include "src/compiler/node-properties.h"
19 #include "src/compiler/operation-typer.h"
20 #include "src/compiler/operator-properties.h"
21 #include "src/compiler/representation-change.h"
22 #include "src/compiler/simplified-operator.h"
23 #include "src/compiler/type-cache.h"
24 #include "src/conversions-inl.h"
25 #include "src/objects.h"
26
27 namespace v8 {
28 namespace internal {
29 namespace compiler {
30
31 // Macro for outputting trace information from representation inference.
32 #define TRACE(...) \
33 do { \
34 if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
35 } while (false)
36
37 // Representation selection and lowering of {Simplified} operators to machine
38 // operators are interwined. We use a fixpoint calculation to compute both the
39 // output representation and the best possible lowering for {Simplified} nodes.
40 // Representation change insertion ensures that all values are in the correct
41 // machine representation after this phase, as dictated by the machine
42 // operators themselves.
43 enum Phase {
44 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
45 // backwards from uses to definitions, around cycles in phis, according
46 // to local rules for each operator.
47 // During this phase, the usage information for a node determines the best
48 // possible lowering for each operator so far, and that in turn determines
49 // the output representation.
50 // Therefore, to be correct, this phase must iterate to a fixpoint before
51 // the next phase can begin.
52 PROPAGATE,
53
54 // 2.) RETYPE: Propagate types from type feedback forwards.
55 RETYPE,
56
57 // 3.) LOWER: perform lowering for all {Simplified} nodes by replacing some
58 // operators for some nodes, expanding some nodes to multiple nodes, or
59 // removing some (redundant) nodes.
60 // During this phase, use the {RepresentationChanger} to insert
61 // representation changes between uses that demand a particular
62 // representation and nodes that produce a different representation.
63 LOWER
64 };
65
66 namespace {
67
MachineRepresentationFromArrayType(ExternalArrayType array_type)68 MachineRepresentation MachineRepresentationFromArrayType(
69 ExternalArrayType array_type) {
70 switch (array_type) {
71 case kExternalUint8Array:
72 case kExternalUint8ClampedArray:
73 case kExternalInt8Array:
74 return MachineRepresentation::kWord8;
75 case kExternalUint16Array:
76 case kExternalInt16Array:
77 return MachineRepresentation::kWord16;
78 case kExternalUint32Array:
79 case kExternalInt32Array:
80 return MachineRepresentation::kWord32;
81 case kExternalFloat32Array:
82 return MachineRepresentation::kFloat32;
83 case kExternalFloat64Array:
84 return MachineRepresentation::kFloat64;
85 }
86 UNREACHABLE();
87 return MachineRepresentation::kNone;
88 }
89
CheckedUseInfoAsWord32FromHint(NumberOperationHint hint,CheckForMinusZeroMode minus_zero_mode=CheckForMinusZeroMode::kCheckForMinusZero)90 UseInfo CheckedUseInfoAsWord32FromHint(
91 NumberOperationHint hint, CheckForMinusZeroMode minus_zero_mode =
92 CheckForMinusZeroMode::kCheckForMinusZero) {
93 switch (hint) {
94 case NumberOperationHint::kSignedSmall:
95 return UseInfo::CheckedSignedSmallAsWord32(minus_zero_mode);
96 case NumberOperationHint::kSigned32:
97 return UseInfo::CheckedSigned32AsWord32(minus_zero_mode);
98 case NumberOperationHint::kNumber:
99 return UseInfo::CheckedNumberAsWord32();
100 case NumberOperationHint::kNumberOrOddball:
101 return UseInfo::CheckedNumberOrOddballAsWord32();
102 }
103 UNREACHABLE();
104 return UseInfo::None();
105 }
106
CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint)107 UseInfo CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint) {
108 switch (hint) {
109 case NumberOperationHint::kSignedSmall:
110 case NumberOperationHint::kSigned32:
111 // Not used currently.
112 UNREACHABLE();
113 break;
114 case NumberOperationHint::kNumber:
115 return UseInfo::CheckedNumberAsFloat64();
116 case NumberOperationHint::kNumberOrOddball:
117 return UseInfo::CheckedNumberOrOddballAsFloat64();
118 }
119 UNREACHABLE();
120 return UseInfo::None();
121 }
122
TruncatingUseInfoFromRepresentation(MachineRepresentation rep)123 UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
124 switch (rep) {
125 case MachineRepresentation::kTaggedSigned:
126 case MachineRepresentation::kTaggedPointer:
127 case MachineRepresentation::kTagged:
128 return UseInfo::AnyTagged();
129 case MachineRepresentation::kFloat64:
130 return UseInfo::TruncatingFloat64();
131 case MachineRepresentation::kFloat32:
132 return UseInfo::Float32();
133 case MachineRepresentation::kWord64:
134 return UseInfo::TruncatingWord64();
135 case MachineRepresentation::kWord8:
136 case MachineRepresentation::kWord16:
137 case MachineRepresentation::kWord32:
138 return UseInfo::TruncatingWord32();
139 case MachineRepresentation::kBit:
140 return UseInfo::Bool();
141 case MachineRepresentation::kSimd128:
142 case MachineRepresentation::kSimd1x4:
143 case MachineRepresentation::kSimd1x8:
144 case MachineRepresentation::kSimd1x16:
145 case MachineRepresentation::kNone:
146 break;
147 }
148 UNREACHABLE();
149 return UseInfo::None();
150 }
151
152
UseInfoForBasePointer(const FieldAccess & access)153 UseInfo UseInfoForBasePointer(const FieldAccess& access) {
154 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
155 }
156
157
UseInfoForBasePointer(const ElementAccess & access)158 UseInfo UseInfoForBasePointer(const ElementAccess& access) {
159 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
160 }
161
ReplaceEffectControlUses(Node * node,Node * effect,Node * control)162 void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
163 for (Edge edge : node->use_edges()) {
164 if (NodeProperties::IsControlEdge(edge)) {
165 edge.UpdateTo(control);
166 } else if (NodeProperties::IsEffectEdge(edge)) {
167 edge.UpdateTo(effect);
168 } else {
169 DCHECK(NodeProperties::IsValueEdge(edge) ||
170 NodeProperties::IsContextEdge(edge));
171 }
172 }
173 }
174
ChangeToPureOp(Node * node,const Operator * new_op)175 void ChangeToPureOp(Node* node, const Operator* new_op) {
176 DCHECK(new_op->HasProperty(Operator::kPure));
177 if (node->op()->EffectInputCount() > 0) {
178 DCHECK_LT(0, node->op()->ControlInputCount());
179 // Disconnect the node from effect and control chains.
180 Node* control = NodeProperties::GetControlInput(node);
181 Node* effect = NodeProperties::GetEffectInput(node);
182 ReplaceEffectControlUses(node, effect, control);
183 node->TrimInputCount(new_op->ValueInputCount());
184 } else {
185 DCHECK_EQ(0, node->op()->ControlInputCount());
186 }
187 NodeProperties::ChangeOp(node, new_op);
188 }
189
190 #ifdef DEBUG
191 // Helpers for monotonicity checking.
192 class InputUseInfos {
193 public:
InputUseInfos(Zone * zone)194 explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
195
SetAndCheckInput(Node * node,int index,UseInfo use_info)196 void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
197 if (input_use_infos_.empty()) {
198 input_use_infos_.resize(node->InputCount(), UseInfo::None());
199 }
200 // Check that the new use informatin is a super-type of the old
201 // one.
202 CHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
203 input_use_infos_[index] = use_info;
204 }
205
206 private:
207 ZoneVector<UseInfo> input_use_infos_;
208
IsUseLessGeneral(UseInfo use1,UseInfo use2)209 static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
210 return use1.truncation().IsLessGeneralThan(use2.truncation());
211 }
212 };
213
214 #endif // DEBUG
215
CanOverflowSigned32(const Operator * op,Type * left,Type * right,Zone * type_zone)216 bool CanOverflowSigned32(const Operator* op, Type* left, Type* right,
217 Zone* type_zone) {
218 // We assume the inputs are checked Signed32 (or known statically
219 // to be Signed32). Technically, theinputs could also be minus zero, but
220 // that cannot cause overflow.
221 left = Type::Intersect(left, Type::Signed32(), type_zone);
222 right = Type::Intersect(right, Type::Signed32(), type_zone);
223 if (!left->IsInhabited() || !right->IsInhabited()) return false;
224 switch (op->opcode()) {
225 case IrOpcode::kSpeculativeNumberAdd:
226 return (left->Max() + right->Max() > kMaxInt) ||
227 (left->Min() + right->Min() < kMinInt);
228
229 case IrOpcode::kSpeculativeNumberSubtract:
230 return (left->Max() - right->Min() > kMaxInt) ||
231 (left->Min() - right->Max() < kMinInt);
232
233 default:
234 UNREACHABLE();
235 }
236 return true;
237 }
238
239 } // namespace
240
241 class RepresentationSelector {
242 public:
243 // Information for each node tracked during the fixpoint.
244 class NodeInfo final {
245 public:
246 // Adds new use to the node. Returns true if something has changed
247 // and the node has to be requeued.
AddUse(UseInfo info)248 bool AddUse(UseInfo info) {
249 Truncation old_truncation = truncation_;
250 truncation_ = Truncation::Generalize(truncation_, info.truncation());
251 return truncation_ != old_truncation;
252 }
253
set_queued()254 void set_queued() { state_ = kQueued; }
set_visited()255 void set_visited() { state_ = kVisited; }
set_pushed()256 void set_pushed() { state_ = kPushed; }
reset_state()257 void reset_state() { state_ = kUnvisited; }
visited() const258 bool visited() const { return state_ == kVisited; }
queued() const259 bool queued() const { return state_ == kQueued; }
unvisited() const260 bool unvisited() const { return state_ == kUnvisited; }
truncation() const261 Truncation truncation() const { return truncation_; }
set_output(MachineRepresentation output)262 void set_output(MachineRepresentation output) { representation_ = output; }
263
representation() const264 MachineRepresentation representation() const { return representation_; }
265
266 // Helpers for feedback typing.
set_feedback_type(Type * type)267 void set_feedback_type(Type* type) { feedback_type_ = type; }
feedback_type() const268 Type* feedback_type() const { return feedback_type_; }
set_weakened()269 void set_weakened() { weakened_ = true; }
weakened() const270 bool weakened() const { return weakened_; }
set_restriction_type(Type * type)271 void set_restriction_type(Type* type) { restriction_type_ = type; }
restriction_type() const272 Type* restriction_type() const { return restriction_type_; }
273
274 private:
275 enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
276 State state_ = kUnvisited;
277 MachineRepresentation representation_ =
278 MachineRepresentation::kNone; // Output representation.
279 Truncation truncation_ = Truncation::None(); // Information about uses.
280
281 Type* restriction_type_ = Type::Any();
282 Type* feedback_type_ = nullptr;
283 bool weakened_ = false;
284 };
285
RepresentationSelector(JSGraph * jsgraph,Zone * zone,RepresentationChanger * changer,SourcePositionTable * source_positions)286 RepresentationSelector(JSGraph* jsgraph, Zone* zone,
287 RepresentationChanger* changer,
288 SourcePositionTable* source_positions)
289 : jsgraph_(jsgraph),
290 zone_(zone),
291 count_(jsgraph->graph()->NodeCount()),
292 info_(count_, zone),
293 #ifdef DEBUG
294 node_input_use_infos_(count_, InputUseInfos(zone), zone),
295 #endif
296 nodes_(zone),
297 replacements_(zone),
298 phase_(PROPAGATE),
299 changer_(changer),
300 queue_(zone),
301 typing_stack_(zone),
302 source_positions_(source_positions),
303 type_cache_(TypeCache::Get()),
304 op_typer_(jsgraph->isolate(), graph_zone()) {
305 }
306
307 // Forward propagation of types from type feedback.
RunTypePropagationPhase()308 void RunTypePropagationPhase() {
309 // Run type propagation.
310 TRACE("--{Type propagation phase}--\n");
311 phase_ = RETYPE;
312 ResetNodeInfoState();
313
314 DCHECK(typing_stack_.empty());
315 typing_stack_.push({graph()->end(), 0});
316 GetInfo(graph()->end())->set_pushed();
317 while (!typing_stack_.empty()) {
318 NodeState& current = typing_stack_.top();
319
320 // If there is an unvisited input, push it and continue.
321 bool pushed_unvisited = false;
322 while (current.input_index < current.node->InputCount()) {
323 Node* input = current.node->InputAt(current.input_index);
324 NodeInfo* input_info = GetInfo(input);
325 current.input_index++;
326 if (input_info->unvisited()) {
327 input_info->set_pushed();
328 typing_stack_.push({input, 0});
329 pushed_unvisited = true;
330 break;
331 }
332 }
333 if (pushed_unvisited) continue;
334
335 // Process the top of the stack.
336 Node* node = current.node;
337 typing_stack_.pop();
338 NodeInfo* info = GetInfo(node);
339 info->set_visited();
340 bool updated = UpdateFeedbackType(node);
341 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
342 VisitNode(node, info->truncation(), nullptr);
343 TRACE(" ==> output ");
344 PrintOutputInfo(info);
345 TRACE("\n");
346 if (updated) {
347 for (Node* const user : node->uses()) {
348 if (GetInfo(user)->visited()) {
349 GetInfo(user)->set_queued();
350 queue_.push(user);
351 }
352 }
353 }
354 }
355
356 // Process the revisit queue.
357 while (!queue_.empty()) {
358 Node* node = queue_.front();
359 queue_.pop();
360 NodeInfo* info = GetInfo(node);
361 info->set_visited();
362 bool updated = UpdateFeedbackType(node);
363 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
364 VisitNode(node, info->truncation(), nullptr);
365 TRACE(" ==> output ");
366 PrintOutputInfo(info);
367 TRACE("\n");
368 if (updated) {
369 for (Node* const user : node->uses()) {
370 if (GetInfo(user)->visited()) {
371 GetInfo(user)->set_queued();
372 queue_.push(user);
373 }
374 }
375 }
376 }
377 }
378
ResetNodeInfoState()379 void ResetNodeInfoState() {
380 // Clean up for the next phase.
381 for (NodeInfo& info : info_) {
382 info.reset_state();
383 }
384 }
385
TypeOf(Node * node)386 Type* TypeOf(Node* node) {
387 Type* type = GetInfo(node)->feedback_type();
388 return type == nullptr ? NodeProperties::GetType(node) : type;
389 }
390
FeedbackTypeOf(Node * node)391 Type* FeedbackTypeOf(Node* node) {
392 Type* type = GetInfo(node)->feedback_type();
393 return type == nullptr ? Type::None() : type;
394 }
395
TypePhi(Node * node)396 Type* TypePhi(Node* node) {
397 int arity = node->op()->ValueInputCount();
398 Type* type = FeedbackTypeOf(node->InputAt(0));
399 for (int i = 1; i < arity; ++i) {
400 type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
401 }
402 return type;
403 }
404
TypeSelect(Node * node)405 Type* TypeSelect(Node* node) {
406 return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
407 FeedbackTypeOf(node->InputAt(2)));
408 }
409
UpdateFeedbackType(Node * node)410 bool UpdateFeedbackType(Node* node) {
411 if (node->op()->ValueOutputCount() == 0) return false;
412
413 NodeInfo* info = GetInfo(node);
414 Type* type = info->feedback_type();
415 Type* new_type = type;
416
417 // For any non-phi node just wait until we get all inputs typed. We only
418 // allow untyped inputs for phi nodes because phis are the only places
419 // where cycles need to be broken.
420 if (node->opcode() != IrOpcode::kPhi) {
421 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
422 if (GetInfo(node->InputAt(i))->feedback_type() == nullptr) {
423 return false;
424 }
425 }
426 }
427
428 switch (node->opcode()) {
429 #define DECLARE_CASE(Name) \
430 case IrOpcode::k##Name: { \
431 new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
432 FeedbackTypeOf(node->InputAt(1))); \
433 break; \
434 }
435 SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
436 #undef DECLARE_CASE
437
438 #define DECLARE_CASE(Name) \
439 case IrOpcode::k##Name: { \
440 new_type = \
441 Type::Intersect(op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
442 FeedbackTypeOf(node->InputAt(1))), \
443 info->restriction_type(), graph_zone()); \
444 break; \
445 }
446 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
447 #undef DECLARE_CASE
448
449 #define DECLARE_CASE(Name) \
450 case IrOpcode::k##Name: { \
451 new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0))); \
452 break; \
453 }
454 SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
455 #undef DECLARE_CASE
456
457 case IrOpcode::kPlainPrimitiveToNumber:
458 new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
459 break;
460
461 case IrOpcode::kPhi: {
462 new_type = TypePhi(node);
463 if (type != nullptr) {
464 new_type = Weaken(node, type, new_type);
465 }
466 break;
467 }
468
469 case IrOpcode::kTypeGuard: {
470 new_type = op_typer_.TypeTypeGuard(node->op(),
471 FeedbackTypeOf(node->InputAt(0)));
472 break;
473 }
474
475 case IrOpcode::kSelect: {
476 new_type = TypeSelect(node);
477 break;
478 }
479
480 default:
481 // Shortcut for operations that we do not handle.
482 if (type == nullptr) {
483 GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
484 return true;
485 }
486 return false;
487 }
488 // We need to guarantee that the feedback type is a subtype of the upper
489 // bound. Naively that should hold, but weakening can actually produce
490 // a bigger type if we are unlucky with ordering of phi typing. To be
491 // really sure, just intersect the upper bound with the feedback type.
492 new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());
493
494 if (type != nullptr && new_type->Is(type)) return false;
495 GetInfo(node)->set_feedback_type(new_type);
496 if (FLAG_trace_representation) {
497 PrintNodeFeedbackType(node);
498 }
499 return true;
500 }
501
PrintNodeFeedbackType(Node * n)502 void PrintNodeFeedbackType(Node* n) {
503 OFStream os(stdout);
504 os << "#" << n->id() << ":" << *n->op() << "(";
505 int j = 0;
506 for (Node* const i : n->inputs()) {
507 if (j++ > 0) os << ", ";
508 os << "#" << i->id() << ":" << i->op()->mnemonic();
509 }
510 os << ")";
511 if (NodeProperties::IsTyped(n)) {
512 os << " [Static type: ";
513 Type* static_type = NodeProperties::GetType(n);
514 static_type->PrintTo(os);
515 Type* feedback_type = GetInfo(n)->feedback_type();
516 if (feedback_type != nullptr && feedback_type != static_type) {
517 os << ", Feedback type: ";
518 feedback_type->PrintTo(os);
519 }
520 os << "]";
521 }
522 os << std::endl;
523 }
524
Weaken(Node * node,Type * previous_type,Type * current_type)525 Type* Weaken(Node* node, Type* previous_type, Type* current_type) {
526 // If the types have nothing to do with integers, return the types.
527 Type* const integer = type_cache_.kInteger;
528 if (!previous_type->Maybe(integer)) {
529 return current_type;
530 }
531 DCHECK(current_type->Maybe(integer));
532
533 Type* current_integer =
534 Type::Intersect(current_type, integer, graph_zone());
535 Type* previous_integer =
536 Type::Intersect(previous_type, integer, graph_zone());
537
538 // Once we start weakening a node, we should always weaken.
539 if (!GetInfo(node)->weakened()) {
540 // Only weaken if there is range involved; we should converge quickly
541 // for all other types (the exception is a union of many constants,
542 // but we currently do not increase the number of constants in unions).
543 Type* previous = previous_integer->GetRange();
544 Type* current = current_integer->GetRange();
545 if (current == nullptr || previous == nullptr) {
546 return current_type;
547 }
548 // Range is involved => we are weakening.
549 GetInfo(node)->set_weakened();
550 }
551
552 return Type::Union(current_type,
553 op_typer_.WeakenRange(previous_integer, current_integer),
554 graph_zone());
555 }
556
557 // Backward propagation of truncations.
RunTruncationPropagationPhase()558 void RunTruncationPropagationPhase() {
559 // Run propagation phase to a fixpoint.
560 TRACE("--{Propagation phase}--\n");
561 phase_ = PROPAGATE;
562 EnqueueInitial(jsgraph_->graph()->end());
563 // Process nodes from the queue until it is empty.
564 while (!queue_.empty()) {
565 Node* node = queue_.front();
566 NodeInfo* info = GetInfo(node);
567 queue_.pop();
568 info->set_visited();
569 TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
570 info->truncation().description());
571 VisitNode(node, info->truncation(), nullptr);
572 }
573 }
574
Run(SimplifiedLowering * lowering)575 void Run(SimplifiedLowering* lowering) {
576 RunTruncationPropagationPhase();
577
578 RunTypePropagationPhase();
579
580 // Run lowering and change insertion phase.
581 TRACE("--{Simplified lowering phase}--\n");
582 phase_ = LOWER;
583 // Process nodes from the collected {nodes_} vector.
584 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
585 Node* node = *i;
586 NodeInfo* info = GetInfo(node);
587 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
588 // Reuse {VisitNode()} so the representation rules are in one place.
589 SourcePositionTable::Scope scope(
590 source_positions_, source_positions_->GetSourcePosition(node));
591 VisitNode(node, info->truncation(), lowering);
592 }
593
594 // Perform the final replacements.
595 for (NodeVector::iterator i = replacements_.begin();
596 i != replacements_.end(); ++i) {
597 Node* node = *i;
598 Node* replacement = *(++i);
599 node->ReplaceUses(replacement);
600 node->Kill();
601 // We also need to replace the node in the rest of the vector.
602 for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
603 ++j;
604 if (*j == node) *j = replacement;
605 }
606 }
607 }
608
EnqueueInitial(Node * node)609 void EnqueueInitial(Node* node) {
610 NodeInfo* info = GetInfo(node);
611 info->set_queued();
612 nodes_.push_back(node);
613 queue_.push(node);
614 }
615
616 // Enqueue {use_node}'s {index} input if the {use} contains new information
617 // for that input node. Add the input to {nodes_} if this is the first time
618 // it's been visited.
EnqueueInput(Node * use_node,int index,UseInfo use_info=UseInfo::None ())619 void EnqueueInput(Node* use_node, int index,
620 UseInfo use_info = UseInfo::None()) {
621 Node* node = use_node->InputAt(index);
622 if (phase_ != PROPAGATE) return;
623 NodeInfo* info = GetInfo(node);
624 #ifdef DEBUG
625 // Check monotonicity of input requirements.
626 node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
627 use_info);
628 #endif // DEBUG
629 if (info->unvisited()) {
630 // First visit of this node.
631 info->set_queued();
632 nodes_.push_back(node);
633 queue_.push(node);
634 TRACE(" initial #%i: ", node->id());
635 info->AddUse(use_info);
636 PrintTruncation(info->truncation());
637 return;
638 }
639 TRACE(" queue #%i?: ", node->id());
640 PrintTruncation(info->truncation());
641 if (info->AddUse(use_info)) {
642 // New usage information for the node is available.
643 if (!info->queued()) {
644 queue_.push(node);
645 info->set_queued();
646 TRACE(" added: ");
647 } else {
648 TRACE(" inqueue: ");
649 }
650 PrintTruncation(info->truncation());
651 }
652 }
653
lower() const654 bool lower() const { return phase_ == LOWER; }
retype() const655 bool retype() const { return phase_ == RETYPE; }
propagate() const656 bool propagate() const { return phase_ == PROPAGATE; }
657
SetOutput(Node * node,MachineRepresentation representation,Type * restriction_type=Type::Any ())658 void SetOutput(Node* node, MachineRepresentation representation,
659 Type* restriction_type = Type::Any()) {
660 NodeInfo* const info = GetInfo(node);
661 switch (phase_) {
662 case PROPAGATE:
663 info->set_restriction_type(restriction_type);
664 break;
665 case RETYPE:
666 DCHECK(info->restriction_type()->Is(restriction_type));
667 DCHECK(restriction_type->Is(info->restriction_type()));
668 info->set_output(representation);
669 break;
670 case LOWER:
671 DCHECK_EQ(info->representation(), representation);
672 DCHECK(info->restriction_type()->Is(restriction_type));
673 DCHECK(restriction_type->Is(info->restriction_type()));
674 break;
675 }
676 }
677
GetUpperBound(Node * node)678 Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
679
InputCannotBe(Node * node,Type * type)680 bool InputCannotBe(Node* node, Type* type) {
681 DCHECK_EQ(1, node->op()->ValueInputCount());
682 return !GetUpperBound(node->InputAt(0))->Maybe(type);
683 }
684
InputIs(Node * node,Type * type)685 bool InputIs(Node* node, Type* type) {
686 DCHECK_EQ(1, node->op()->ValueInputCount());
687 return GetUpperBound(node->InputAt(0))->Is(type);
688 }
689
BothInputsAreSigned32(Node * node)690 bool BothInputsAreSigned32(Node* node) {
691 return BothInputsAre(node, Type::Signed32());
692 }
693
BothInputsAreUnsigned32(Node * node)694 bool BothInputsAreUnsigned32(Node* node) {
695 return BothInputsAre(node, Type::Unsigned32());
696 }
697
BothInputsAre(Node * node,Type * type)698 bool BothInputsAre(Node* node, Type* type) {
699 DCHECK_EQ(2, node->op()->ValueInputCount());
700 return GetUpperBound(node->InputAt(0))->Is(type) &&
701 GetUpperBound(node->InputAt(1))->Is(type);
702 }
703
IsNodeRepresentationTagged(Node * node)704 bool IsNodeRepresentationTagged(Node* node) {
705 MachineRepresentation representation = GetInfo(node)->representation();
706 return IsAnyTagged(representation);
707 }
708
OneInputCannotBe(Node * node,Type * type)709 bool OneInputCannotBe(Node* node, Type* type) {
710 DCHECK_EQ(2, node->op()->ValueInputCount());
711 return !GetUpperBound(node->InputAt(0))->Maybe(type) ||
712 !GetUpperBound(node->InputAt(1))->Maybe(type);
713 }
714
ConvertInput(Node * node,int index,UseInfo use)715 void ConvertInput(Node* node, int index, UseInfo use) {
716 Node* input = node->InputAt(index);
717 // In the change phase, insert a change before the use if necessary.
718 if (use.representation() == MachineRepresentation::kNone)
719 return; // No input requirement on the use.
720 DCHECK_NOT_NULL(input);
721 NodeInfo* input_info = GetInfo(input);
722 MachineRepresentation input_rep = input_info->representation();
723 if (input_rep != use.representation() ||
724 use.type_check() != TypeCheckKind::kNone) {
725 // Output representation doesn't match usage.
726 TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
727 index, input->id(), input->op()->mnemonic());
728 TRACE(" from ");
729 PrintOutputInfo(input_info);
730 TRACE(" to ");
731 PrintUseInfo(use);
732 TRACE("\n");
733 Node* n = changer_->GetRepresentationFor(
734 input, input_info->representation(), TypeOf(input), node, use);
735 node->ReplaceInput(index, n);
736 }
737 }
738
ProcessInput(Node * node,int index,UseInfo use)739 void ProcessInput(Node* node, int index, UseInfo use) {
740 switch (phase_) {
741 case PROPAGATE:
742 EnqueueInput(node, index, use);
743 break;
744 case RETYPE:
745 break;
746 case LOWER:
747 ConvertInput(node, index, use);
748 break;
749 }
750 }
751
ProcessRemainingInputs(Node * node,int index)752 void ProcessRemainingInputs(Node* node, int index) {
753 DCHECK_GE(index, NodeProperties::PastValueIndex(node));
754 DCHECK_GE(index, NodeProperties::PastContextIndex(node));
755 for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
756 i < NodeProperties::PastEffectIndex(node); ++i) {
757 EnqueueInput(node, i); // Effect inputs: just visit
758 }
759 for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
760 i < NodeProperties::PastControlIndex(node); ++i) {
761 EnqueueInput(node, i); // Control inputs: just visit
762 }
763 }
764
765 // The default, most general visitation case. For {node}, process all value,
766 // context, frame state, effect, and control inputs, assuming that value
767 // inputs should have {kRepTagged} representation and can observe all output
768 // values {kTypeAny}.
VisitInputs(Node * node)769 void VisitInputs(Node* node) {
770 int tagged_count = node->op()->ValueInputCount() +
771 OperatorProperties::GetContextInputCount(node->op()) +
772 OperatorProperties::GetFrameStateInputCount(node->op());
773 // Visit value, context and frame state inputs as tagged.
774 for (int i = 0; i < tagged_count; i++) {
775 ProcessInput(node, i, UseInfo::AnyTagged());
776 }
777 // Only enqueue other inputs (effects, control).
778 for (int i = tagged_count; i < node->InputCount(); i++) {
779 EnqueueInput(node, i);
780 }
781 }
782
VisitReturn(Node * node)783 void VisitReturn(Node* node) {
784 int tagged_limit = node->op()->ValueInputCount() +
785 OperatorProperties::GetContextInputCount(node->op()) +
786 OperatorProperties::GetFrameStateInputCount(node->op());
787 // Visit integer slot count to pop
788 ProcessInput(node, 0, UseInfo::TruncatingWord32());
789
790 // Visit value, context and frame state inputs as tagged.
791 for (int i = 1; i < tagged_limit; i++) {
792 ProcessInput(node, i, UseInfo::AnyTagged());
793 }
794 // Only enqueue other inputs (effects, control).
795 for (int i = tagged_limit; i < node->InputCount(); i++) {
796 EnqueueInput(node, i);
797 }
798 }
799
800 // Helper for an unused node.
VisitUnused(Node * node)801 void VisitUnused(Node* node) {
802 int value_count = node->op()->ValueInputCount() +
803 OperatorProperties::GetContextInputCount(node->op()) +
804 OperatorProperties::GetFrameStateInputCount(node->op());
805 for (int i = 0; i < value_count; i++) {
806 ProcessInput(node, i, UseInfo::None());
807 }
808 ProcessRemainingInputs(node, value_count);
809 if (lower()) Kill(node);
810 }
811
812 // Helper for binops of the R x L -> O variety.
VisitBinop(Node * node,UseInfo left_use,UseInfo right_use,MachineRepresentation output,Type * restriction_type=Type::Any ())813 void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
814 MachineRepresentation output,
815 Type* restriction_type = Type::Any()) {
816 DCHECK_EQ(2, node->op()->ValueInputCount());
817 ProcessInput(node, 0, left_use);
818 ProcessInput(node, 1, right_use);
819 for (int i = 2; i < node->InputCount(); i++) {
820 EnqueueInput(node, i);
821 }
822 SetOutput(node, output, restriction_type);
823 }
824
825 // Helper for binops of the I x I -> O variety.
VisitBinop(Node * node,UseInfo input_use,MachineRepresentation output,Type * restriction_type=Type::Any ())826 void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output,
827 Type* restriction_type = Type::Any()) {
828 VisitBinop(node, input_use, input_use, output, restriction_type);
829 }
830
VisitSpeculativeInt32Binop(Node * node)831 void VisitSpeculativeInt32Binop(Node* node) {
832 DCHECK_EQ(2, node->op()->ValueInputCount());
833 if (BothInputsAre(node, Type::NumberOrOddball())) {
834 return VisitBinop(node, UseInfo::TruncatingWord32(),
835 MachineRepresentation::kWord32);
836 }
837 NumberOperationHint hint = NumberOperationHintOf(node->op());
838 return VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
839 MachineRepresentation::kWord32);
840 }
841
842 // Helper for unops of the I -> O variety.
VisitUnop(Node * node,UseInfo input_use,MachineRepresentation output)843 void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output) {
844 DCHECK_EQ(1, node->op()->ValueInputCount());
845 ProcessInput(node, 0, input_use);
846 ProcessRemainingInputs(node, 1);
847 SetOutput(node, output);
848 }
849
850 // Helper for leaf nodes.
VisitLeaf(Node * node,MachineRepresentation output)851 void VisitLeaf(Node* node, MachineRepresentation output) {
852 DCHECK_EQ(0, node->InputCount());
853 SetOutput(node, output);
854 }
855
856 // Helpers for specific types of binops.
VisitFloat64Binop(Node * node)857 void VisitFloat64Binop(Node* node) {
858 VisitBinop(node, UseInfo::TruncatingFloat64(),
859 MachineRepresentation::kFloat64);
860 }
VisitWord32TruncatingBinop(Node * node)861 void VisitWord32TruncatingBinop(Node* node) {
862 VisitBinop(node, UseInfo::TruncatingWord32(),
863 MachineRepresentation::kWord32);
864 }
865
866 // Infer representation for phi-like nodes.
867 // The {node} parameter is only used to decide on the int64 representation.
868 // Once the type system supports an external pointer type, the {node}
869 // parameter can be removed.
GetOutputInfoForPhi(Node * node,Type * type,Truncation use)870 MachineRepresentation GetOutputInfoForPhi(Node* node, Type* type,
871 Truncation use) {
872 // Compute the representation.
873 if (type->Is(Type::None())) {
874 return MachineRepresentation::kNone;
875 } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
876 return MachineRepresentation::kWord32;
877 } else if (type->Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
878 return MachineRepresentation::kWord32;
879 } else if (type->Is(Type::Boolean())) {
880 return MachineRepresentation::kBit;
881 } else if (type->Is(Type::NumberOrOddball()) && use.IsUsedAsFloat64()) {
882 return MachineRepresentation::kFloat64;
883 } else if (type->Is(
884 Type::Union(Type::SignedSmall(), Type::NaN(), zone()))) {
885 // TODO(turbofan): For Phis that return either NaN or some Smi, it's
886 // beneficial to not go all the way to double, unless the uses are
887 // double uses. For tagging that just means some potentially expensive
888 // allocation code; we might want to do the same for -0 as well?
889 return MachineRepresentation::kTagged;
890 } else if (type->Is(Type::Number())) {
891 return MachineRepresentation::kFloat64;
892 } else if (type->Is(Type::ExternalPointer())) {
893 return MachineType::PointerRepresentation();
894 }
895 return MachineRepresentation::kTagged;
896 }
897
898 // Helper for handling selects.
VisitSelect(Node * node,Truncation truncation,SimplifiedLowering * lowering)899 void VisitSelect(Node* node, Truncation truncation,
900 SimplifiedLowering* lowering) {
901 DCHECK(TypeOf(node->InputAt(0))->Is(Type::Boolean()));
902 ProcessInput(node, 0, UseInfo::Bool());
903
904 MachineRepresentation output =
905 GetOutputInfoForPhi(node, TypeOf(node), truncation);
906 SetOutput(node, output);
907
908 if (lower()) {
909 // Update the select operator.
910 SelectParameters p = SelectParametersOf(node->op());
911 if (output != p.representation()) {
912 NodeProperties::ChangeOp(node,
913 lowering->common()->Select(output, p.hint()));
914 }
915 }
916 // Convert inputs to the output representation of this phi, pass the
917 // truncation truncation along.
918 UseInfo input_use(output, truncation);
919 ProcessInput(node, 1, input_use);
920 ProcessInput(node, 2, input_use);
921 }
922
923 // Helper for handling phis.
VisitPhi(Node * node,Truncation truncation,SimplifiedLowering * lowering)924 void VisitPhi(Node* node, Truncation truncation,
925 SimplifiedLowering* lowering) {
926 MachineRepresentation output =
927 GetOutputInfoForPhi(node, TypeOf(node), truncation);
928 // Only set the output representation if not running with type
929 // feedback. (Feedback typing will set the representation.)
930 SetOutput(node, output);
931
932 int values = node->op()->ValueInputCount();
933 if (lower()) {
934 // Update the phi operator.
935 if (output != PhiRepresentationOf(node->op())) {
936 NodeProperties::ChangeOp(node, lowering->common()->Phi(output, values));
937 }
938 }
939
940 // Convert inputs to the output representation of this phi, pass the
941 // truncation along.
942 UseInfo input_use(output, truncation);
943 for (int i = 0; i < node->InputCount(); i++) {
944 ProcessInput(node, i, i < values ? input_use : UseInfo::None());
945 }
946 }
947
VisitObjectIs(Node * node,Type * type,SimplifiedLowering * lowering)948 void VisitObjectIs(Node* node, Type* type, SimplifiedLowering* lowering) {
949 Type* const input_type = TypeOf(node->InputAt(0));
950 if (input_type->Is(type)) {
951 VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
952 if (lower()) {
953 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
954 }
955 } else {
956 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
957 if (lower() && !input_type->Maybe(type)) {
958 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
959 }
960 }
961 }
962
VisitCall(Node * node,SimplifiedLowering * lowering)963 void VisitCall(Node* node, SimplifiedLowering* lowering) {
964 const CallDescriptor* desc = CallDescriptorOf(node->op());
965 int params = static_cast<int>(desc->ParameterCount());
966 int value_input_count = node->op()->ValueInputCount();
967 // Propagate representation information from call descriptor.
968 for (int i = 0; i < value_input_count; i++) {
969 if (i == 0) {
970 // The target of the call.
971 ProcessInput(node, i, UseInfo::Any());
972 } else if ((i - 1) < params) {
973 ProcessInput(node, i, TruncatingUseInfoFromRepresentation(
974 desc->GetInputType(i).representation()));
975 } else {
976 ProcessInput(node, i, UseInfo::AnyTagged());
977 }
978 }
979 ProcessRemainingInputs(node, value_input_count);
980
981 if (desc->ReturnCount() > 0) {
982 SetOutput(node, desc->GetReturnType(0).representation());
983 } else {
984 SetOutput(node, MachineRepresentation::kTagged);
985 }
986 }
987
DeoptValueSemanticOf(Type * type)988 static MachineSemantic DeoptValueSemanticOf(Type* type) {
989 // We only need signedness to do deopt correctly.
990 if (type->Is(Type::Signed32())) {
991 return MachineSemantic::kInt32;
992 } else if (type->Is(Type::Unsigned32())) {
993 return MachineSemantic::kUint32;
994 } else {
995 return MachineSemantic::kAny;
996 }
997 }
998
DeoptMachineTypeOf(MachineRepresentation rep,Type * type)999 static MachineType DeoptMachineTypeOf(MachineRepresentation rep, Type* type) {
1000 if (!type->IsInhabited()) {
1001 return MachineType::None();
1002 }
1003 // TODO(turbofan): Special treatment for ExternalPointer here,
1004 // to avoid incompatible truncations. We really need a story
1005 // for the JSFunction::entry field.
1006 if (type->Is(Type::ExternalPointer())) {
1007 return MachineType::Pointer();
1008 }
1009 // Do not distinguish between various Tagged variations.
1010 if (IsAnyTagged(rep)) {
1011 return MachineType::AnyTagged();
1012 }
1013 MachineType machine_type(rep, DeoptValueSemanticOf(type));
1014 DCHECK(machine_type.representation() != MachineRepresentation::kWord32 ||
1015 machine_type.semantic() == MachineSemantic::kInt32 ||
1016 machine_type.semantic() == MachineSemantic::kUint32);
1017 DCHECK(machine_type.representation() != MachineRepresentation::kBit ||
1018 type->Is(Type::Boolean()));
1019 return machine_type;
1020 }
1021
VisitStateValues(Node * node)1022 void VisitStateValues(Node* node) {
1023 if (propagate()) {
1024 for (int i = 0; i < node->InputCount(); i++) {
1025 EnqueueInput(node, i, UseInfo::Any());
1026 }
1027 } else if (lower()) {
1028 Zone* zone = jsgraph_->zone();
1029 ZoneVector<MachineType>* types =
1030 new (zone->New(sizeof(ZoneVector<MachineType>)))
1031 ZoneVector<MachineType>(node->InputCount(), zone);
1032 for (int i = 0; i < node->InputCount(); i++) {
1033 Node* input = node->InputAt(i);
1034 (*types)[i] =
1035 DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1036 }
1037 SparseInputMask mask = SparseInputMaskOf(node->op());
1038 NodeProperties::ChangeOp(
1039 node, jsgraph_->common()->TypedStateValues(types, mask));
1040 }
1041 SetOutput(node, MachineRepresentation::kTagged);
1042 }
1043
VisitObjectState(Node * node)1044 void VisitObjectState(Node* node) {
1045 if (propagate()) {
1046 for (int i = 0; i < node->InputCount(); i++) {
1047 Node* input = node->InputAt(i);
1048 Type* input_type = TypeOf(input);
1049 // TODO(turbofan): Special treatment for ExternalPointer here,
1050 // to avoid incompatible truncations. We really need a story
1051 // for the JSFunction::entry field.
1052 UseInfo use_info = UseInfo::None();
1053 if (input_type->IsInhabited()) {
1054 if (input_type->Is(Type::ExternalPointer())) {
1055 use_info = UseInfo::PointerInt();
1056 } else {
1057 use_info = UseInfo::Any();
1058 }
1059 }
1060 EnqueueInput(node, i, use_info);
1061 }
1062 } else if (lower()) {
1063 Zone* zone = jsgraph_->zone();
1064 ZoneVector<MachineType>* types =
1065 new (zone->New(sizeof(ZoneVector<MachineType>)))
1066 ZoneVector<MachineType>(node->InputCount(), zone);
1067 for (int i = 0; i < node->InputCount(); i++) {
1068 Node* input = node->InputAt(i);
1069 (*types)[i] =
1070 DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1071 }
1072 NodeProperties::ChangeOp(node,
1073 jsgraph_->common()->TypedObjectState(types));
1074 }
1075 SetOutput(node, MachineRepresentation::kTagged);
1076 }
1077
Int32Op(Node * node)1078 const Operator* Int32Op(Node* node) {
1079 return changer_->Int32OperatorFor(node->opcode());
1080 }
1081
Int32OverflowOp(Node * node)1082 const Operator* Int32OverflowOp(Node* node) {
1083 return changer_->Int32OverflowOperatorFor(node->opcode());
1084 }
1085
Uint32Op(Node * node)1086 const Operator* Uint32Op(Node* node) {
1087 return changer_->Uint32OperatorFor(node->opcode());
1088 }
1089
Uint32OverflowOp(Node * node)1090 const Operator* Uint32OverflowOp(Node* node) {
1091 return changer_->Uint32OverflowOperatorFor(node->opcode());
1092 }
1093
Float64Op(Node * node)1094 const Operator* Float64Op(Node* node) {
1095 return changer_->Float64OperatorFor(node->opcode());
1096 }
1097
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,Type * field_type,MachineRepresentation value_representation,Node * value)1098 WriteBarrierKind WriteBarrierKindFor(
1099 BaseTaggedness base_taggedness,
1100 MachineRepresentation field_representation, Type* field_type,
1101 MachineRepresentation value_representation, Node* value) {
1102 if (base_taggedness == kTaggedBase &&
1103 CanBeTaggedPointer(field_representation)) {
1104 Type* value_type = NodeProperties::GetType(value);
1105 if (field_representation == MachineRepresentation::kTaggedSigned ||
1106 value_representation == MachineRepresentation::kTaggedSigned) {
1107 // Write barriers are only for stores of heap objects.
1108 return kNoWriteBarrier;
1109 }
1110 if (field_type->Is(Type::BooleanOrNullOrUndefined()) ||
1111 value_type->Is(Type::BooleanOrNullOrUndefined())) {
1112 // Write barriers are not necessary when storing true, false, null or
1113 // undefined, because these special oddballs are always in the root set.
1114 return kNoWriteBarrier;
1115 }
1116 if (value_type->IsHeapConstant()) {
1117 Heap::RootListIndex root_index;
1118 Heap* heap = jsgraph_->isolate()->heap();
1119 if (heap->IsRootHandle(value_type->AsHeapConstant()->Value(),
1120 &root_index)) {
1121 if (heap->RootIsImmortalImmovable(root_index)) {
1122 // Write barriers are unnecessary for immortal immovable roots.
1123 return kNoWriteBarrier;
1124 }
1125 }
1126 }
1127 if (field_representation == MachineRepresentation::kTaggedPointer ||
1128 value_representation == MachineRepresentation::kTaggedPointer) {
1129 // Write barriers for heap objects are cheaper.
1130 return kPointerWriteBarrier;
1131 }
1132 NumberMatcher m(value);
1133 if (m.HasValue()) {
1134 if (IsSmiDouble(m.Value())) {
1135 // Storing a smi doesn't need a write barrier.
1136 return kNoWriteBarrier;
1137 }
1138 // The NumberConstant will be represented as HeapNumber.
1139 return kPointerWriteBarrier;
1140 }
1141 return kFullWriteBarrier;
1142 }
1143 return kNoWriteBarrier;
1144 }
1145
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,int field_offset,Type * field_type,MachineRepresentation value_representation,Node * value)1146 WriteBarrierKind WriteBarrierKindFor(
1147 BaseTaggedness base_taggedness,
1148 MachineRepresentation field_representation, int field_offset,
1149 Type* field_type, MachineRepresentation value_representation,
1150 Node* value) {
1151 if (base_taggedness == kTaggedBase &&
1152 field_offset == HeapObject::kMapOffset) {
1153 return kMapWriteBarrier;
1154 }
1155 return WriteBarrierKindFor(base_taggedness, field_representation,
1156 field_type, value_representation, value);
1157 }
1158
graph() const1159 Graph* graph() const { return jsgraph_->graph(); }
common() const1160 CommonOperatorBuilder* common() const { return jsgraph_->common(); }
simplified() const1161 SimplifiedOperatorBuilder* simplified() const {
1162 return jsgraph_->simplified();
1163 }
1164
LowerToCheckedInt32Mul(Node * node,Truncation truncation,Type * input0_type,Type * input1_type)1165 void LowerToCheckedInt32Mul(Node* node, Truncation truncation,
1166 Type* input0_type, Type* input1_type) {
1167 // If one of the inputs is positive and/or truncation is being applied,
1168 // there is no need to return -0.
1169 CheckForMinusZeroMode mz_mode =
1170 truncation.IsUsedAsWord32() ||
1171 (input0_type->Is(Type::OrderedNumber()) &&
1172 input0_type->Min() > 0) ||
1173 (input1_type->Is(Type::OrderedNumber()) &&
1174 input1_type->Min() > 0)
1175 ? CheckForMinusZeroMode::kDontCheckForMinusZero
1176 : CheckForMinusZeroMode::kCheckForMinusZero;
1177
1178 NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
1179 }
1180
ChangeToInt32OverflowOp(Node * node)1181 void ChangeToInt32OverflowOp(Node* node) {
1182 NodeProperties::ChangeOp(node, Int32OverflowOp(node));
1183 }
1184
ChangeToUint32OverflowOp(Node * node)1185 void ChangeToUint32OverflowOp(Node* node) {
1186 NodeProperties::ChangeOp(node, Uint32OverflowOp(node));
1187 }
1188
VisitSpeculativeAdditiveOp(Node * node,Truncation truncation,SimplifiedLowering * lowering)1189 void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
1190 SimplifiedLowering* lowering) {
1191 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we can
1192 // only eliminate an unused speculative number operation if we know that
1193 // the inputs are PlainPrimitive, which excludes everything that's might
1194 // have side effects or throws during a ToNumber conversion. We are only
1195 // allowed to perform a number addition if neither input is a String, even
1196 // if the value is never used, so we further limit to NumberOrOddball in
1197 // order to explicitly exclude String inputs.
1198 if (BothInputsAre(node, Type::NumberOrOddball())) {
1199 if (truncation.IsUnused()) return VisitUnused(node);
1200 }
1201
1202 if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
1203 (GetUpperBound(node)->Is(Type::Signed32()) ||
1204 GetUpperBound(node)->Is(Type::Unsigned32()) ||
1205 truncation.IsUsedAsWord32())) {
1206 // => Int32Add/Sub
1207 VisitWord32TruncatingBinop(node);
1208 if (lower()) ChangeToPureOp(node, Int32Op(node));
1209 return;
1210 }
1211
1212 // Try to use type feedback.
1213 NumberOperationHint hint = NumberOperationHintOf(node->op());
1214
1215 if (hint == NumberOperationHint::kSignedSmall ||
1216 hint == NumberOperationHint::kSigned32) {
1217 Type* left_feedback_type = TypeOf(node->InputAt(0));
1218 Type* right_feedback_type = TypeOf(node->InputAt(1));
1219 // Handle the case when no int32 checks on inputs are necessary (but
1220 // an overflow check is needed on the output).
1221 // TODO(jarin) We should not look at the upper bound because the typer
1222 // could have already baked in some feedback into the upper bound.
1223 if (BothInputsAre(node, Type::Signed32()) ||
1224 (BothInputsAre(node, Type::Signed32OrMinusZero()) &&
1225 GetUpperBound(node)->Is(type_cache_.kSafeInteger))) {
1226 VisitBinop(node, UseInfo::TruncatingWord32(),
1227 MachineRepresentation::kWord32, Type::Signed32());
1228 } else {
1229 UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint);
1230 // For CheckedInt32Add and CheckedInt32Sub, we don't need to do
1231 // a minus zero check for the right hand side, since we already
1232 // know that the left hand side is a proper Signed32 value,
1233 // potentially guarded by a check.
1234 UseInfo right_use = CheckedUseInfoAsWord32FromHint(
1235 hint, CheckForMinusZeroMode::kDontCheckForMinusZero);
1236 VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32,
1237 Type::Signed32());
1238 }
1239 if (lower()) {
1240 if (CanOverflowSigned32(node->op(), left_feedback_type,
1241 right_feedback_type, graph_zone())) {
1242 ChangeToInt32OverflowOp(node);
1243 } else {
1244 ChangeToPureOp(node, Int32Op(node));
1245 }
1246 }
1247 return;
1248 }
1249
1250 // default case => Float64Add/Sub
1251 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1252 MachineRepresentation::kFloat64, Type::Number());
1253 if (lower()) {
1254 ChangeToPureOp(node, Float64Op(node));
1255 }
1256 return;
1257 }
1258
VisitSpeculativeNumberModulus(Node * node,Truncation truncation,SimplifiedLowering * lowering)1259 void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
1260 SimplifiedLowering* lowering) {
1261 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1262 // can only eliminate an unused speculative number operation if we know
1263 // that the inputs are PlainPrimitive, which excludes everything that's
1264 // might have side effects or throws during a ToNumber conversion.
1265 if (BothInputsAre(node, Type::PlainPrimitive())) {
1266 if (truncation.IsUnused()) return VisitUnused(node);
1267 }
1268 if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1269 (truncation.IsUsedAsWord32() ||
1270 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1271 // => unsigned Uint32Mod
1272 VisitWord32TruncatingBinop(node);
1273 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1274 return;
1275 }
1276 if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1277 (truncation.IsUsedAsWord32() ||
1278 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1279 // => signed Int32Mod
1280 VisitWord32TruncatingBinop(node);
1281 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1282 return;
1283 }
1284
1285 // Try to use type feedback.
1286 NumberOperationHint hint = NumberOperationHintOf(node->op());
1287
1288 // Handle the case when no uint32 checks on inputs are necessary
1289 // (but an overflow check is needed on the output).
1290 if (BothInputsAreUnsigned32(node)) {
1291 if (hint == NumberOperationHint::kSignedSmall ||
1292 hint == NumberOperationHint::kSigned32) {
1293 VisitBinop(node, UseInfo::TruncatingWord32(),
1294 MachineRepresentation::kWord32, Type::Unsigned32());
1295 if (lower()) ChangeToUint32OverflowOp(node);
1296 return;
1297 }
1298 }
1299
1300 // Handle the case when no int32 checks on inputs are necessary
1301 // (but an overflow check is needed on the output).
1302 if (BothInputsAre(node, Type::Signed32())) {
1303 // If both the inputs the feedback are int32, use the overflow op.
1304 if (hint == NumberOperationHint::kSignedSmall ||
1305 hint == NumberOperationHint::kSigned32) {
1306 VisitBinop(node, UseInfo::TruncatingWord32(),
1307 MachineRepresentation::kWord32, Type::Signed32());
1308 if (lower()) ChangeToInt32OverflowOp(node);
1309 return;
1310 }
1311 }
1312
1313 if (hint == NumberOperationHint::kSignedSmall ||
1314 hint == NumberOperationHint::kSigned32) {
1315 // If the result is truncated, we only need to check the inputs.
1316 if (truncation.IsUsedAsWord32()) {
1317 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1318 MachineRepresentation::kWord32);
1319 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1320 } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
1321 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1322 MachineRepresentation::kWord32, Type::Unsigned32());
1323 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1324 } else {
1325 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1326 MachineRepresentation::kWord32, Type::Signed32());
1327 if (lower()) ChangeToInt32OverflowOp(node);
1328 }
1329 return;
1330 }
1331
1332 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1333 TypeOf(node->InputAt(1))->Is(Type::Unsigned32()) &&
1334 (truncation.IsUsedAsWord32() ||
1335 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1336 // We can only promise Float64 truncation here, as the decision is
1337 // based on the feedback types of the inputs.
1338 VisitBinop(node,
1339 UseInfo(MachineRepresentation::kWord32, Truncation::Float64()),
1340 MachineRepresentation::kWord32, Type::Number());
1341 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1342 return;
1343 }
1344 if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1345 TypeOf(node->InputAt(1))->Is(Type::Signed32()) &&
1346 (truncation.IsUsedAsWord32() ||
1347 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1348 // We can only promise Float64 truncation here, as the decision is
1349 // based on the feedback types of the inputs.
1350 VisitBinop(node,
1351 UseInfo(MachineRepresentation::kWord32, Truncation::Float64()),
1352 MachineRepresentation::kWord32, Type::Number());
1353 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1354 return;
1355 }
1356 // default case => Float64Mod
1357 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1358 MachineRepresentation::kFloat64, Type::Number());
1359 if (lower()) ChangeToPureOp(node, Float64Op(node));
1360 return;
1361 }
1362
VisitOsrGuard(Node * node)1363 void VisitOsrGuard(Node* node) {
1364 VisitInputs(node);
1365
1366 // Insert a dynamic check for the OSR value type if necessary.
1367 switch (OsrGuardTypeOf(node->op())) {
1368 case OsrGuardType::kUninitialized:
1369 // At this point, we should always have a type for the OsrValue.
1370 UNREACHABLE();
1371 break;
1372 case OsrGuardType::kSignedSmall:
1373 if (lower()) {
1374 NodeProperties::ChangeOp(node,
1375 simplified()->CheckedTaggedToTaggedSigned());
1376 }
1377 return SetOutput(node, MachineRepresentation::kTaggedSigned);
1378 case OsrGuardType::kAny: // Nothing to check.
1379 if (lower()) {
1380 DeferReplacement(node, node->InputAt(0));
1381 }
1382 return SetOutput(node, MachineRepresentation::kTagged);
1383 }
1384 UNREACHABLE();
1385 }
1386
1387 // Dispatching routine for visiting the node {node} with the usage {use}.
1388 // Depending on the operator, propagate new usage info to the inputs.
VisitNode(Node * node,Truncation truncation,SimplifiedLowering * lowering)1389 void VisitNode(Node* node, Truncation truncation,
1390 SimplifiedLowering* lowering) {
1391 // Unconditionally eliminate unused pure nodes (only relevant if there's
1392 // a pure operation in between two effectful ones, where the last one
1393 // is unused).
1394 // Note: We must not do this for constants, as they are cached and we
1395 // would thus kill the cached {node} during lowering (i.e. replace all
1396 // uses with Dead), but at that point some node lowering might have
1397 // already taken the constant {node} from the cache (while it was in
1398 // a sane state still) and we would afterwards replace that use with
1399 // Dead as well.
1400 if (node->op()->ValueInputCount() > 0 &&
1401 node->op()->HasProperty(Operator::kPure)) {
1402 if (truncation.IsUnused()) return VisitUnused(node);
1403 }
1404 switch (node->opcode()) {
1405 //------------------------------------------------------------------
1406 // Common operators.
1407 //------------------------------------------------------------------
1408 case IrOpcode::kStart:
1409 // We use Start as a terminator for the frame state chain, so even
1410 // tho Start doesn't really produce a value, we have to say Tagged
1411 // here, otherwise the input conversion will fail.
1412 return VisitLeaf(node, MachineRepresentation::kTagged);
1413 case IrOpcode::kParameter:
1414 // TODO(titzer): use representation from linkage.
1415 return VisitUnop(node, UseInfo::None(), MachineRepresentation::kTagged);
1416 case IrOpcode::kInt32Constant:
1417 return VisitLeaf(node, MachineRepresentation::kWord32);
1418 case IrOpcode::kInt64Constant:
1419 return VisitLeaf(node, MachineRepresentation::kWord64);
1420 case IrOpcode::kExternalConstant:
1421 return VisitLeaf(node, MachineType::PointerRepresentation());
1422 case IrOpcode::kNumberConstant:
1423 return VisitLeaf(node, MachineRepresentation::kTagged);
1424 case IrOpcode::kHeapConstant:
1425 return VisitLeaf(node, MachineRepresentation::kTaggedPointer);
1426 case IrOpcode::kPointerConstant: {
1427 VisitLeaf(node, MachineType::PointerRepresentation());
1428 if (lower()) {
1429 intptr_t const value = OpParameter<intptr_t>(node);
1430 DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
1431 }
1432 return;
1433 }
1434
1435 case IrOpcode::kBranch: {
1436 DCHECK(TypeOf(node->InputAt(0))->Is(Type::Boolean()));
1437 ProcessInput(node, 0, UseInfo::Bool());
1438 EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1439 return;
1440 }
1441 case IrOpcode::kSwitch:
1442 ProcessInput(node, 0, UseInfo::TruncatingWord32());
1443 EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1444 return;
1445 case IrOpcode::kSelect:
1446 return VisitSelect(node, truncation, lowering);
1447 case IrOpcode::kPhi:
1448 return VisitPhi(node, truncation, lowering);
1449 case IrOpcode::kCall:
1450 return VisitCall(node, lowering);
1451
1452 //------------------------------------------------------------------
1453 // JavaScript operators.
1454 //------------------------------------------------------------------
1455 case IrOpcode::kJSToBoolean: {
1456 if (truncation.IsUsedAsBool()) {
1457 ProcessInput(node, 0, UseInfo::Bool());
1458 ProcessInput(node, 1, UseInfo::None());
1459 SetOutput(node, MachineRepresentation::kBit);
1460 if (lower()) DeferReplacement(node, node->InputAt(0));
1461 } else {
1462 VisitInputs(node);
1463 SetOutput(node, MachineRepresentation::kTaggedPointer);
1464 }
1465 return;
1466 }
1467 case IrOpcode::kJSToNumber: {
1468 VisitInputs(node);
1469 // TODO(bmeurer): Optimize somewhat based on input type?
1470 if (truncation.IsUsedAsWord32()) {
1471 SetOutput(node, MachineRepresentation::kWord32);
1472 if (lower()) lowering->DoJSToNumberTruncatesToWord32(node, this);
1473 } else if (truncation.IsUsedAsFloat64()) {
1474 SetOutput(node, MachineRepresentation::kFloat64);
1475 if (lower()) lowering->DoJSToNumberTruncatesToFloat64(node, this);
1476 } else {
1477 SetOutput(node, MachineRepresentation::kTagged);
1478 }
1479 return;
1480 }
1481
1482 //------------------------------------------------------------------
1483 // Simplified operators.
1484 //------------------------------------------------------------------
1485 case IrOpcode::kBooleanNot: {
1486 if (lower()) {
1487 NodeInfo* input_info = GetInfo(node->InputAt(0));
1488 if (input_info->representation() == MachineRepresentation::kBit) {
1489 // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
1490 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
1491 NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
1492 } else {
1493 DCHECK(CanBeTaggedPointer(input_info->representation()));
1494 // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
1495 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
1496 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
1497 }
1498 } else {
1499 // No input representation requirement; adapt during lowering.
1500 ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
1501 SetOutput(node, MachineRepresentation::kBit);
1502 }
1503 return;
1504 }
1505 case IrOpcode::kNumberEqual: {
1506 Type* const lhs_type = TypeOf(node->InputAt(0));
1507 Type* const rhs_type = TypeOf(node->InputAt(1));
1508 // Number comparisons reduce to integer comparisons for integer inputs.
1509 if ((lhs_type->Is(Type::Unsigned32()) &&
1510 rhs_type->Is(Type::Unsigned32())) ||
1511 (lhs_type->Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1512 rhs_type->Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1513 OneInputCannotBe(node, type_cache_.kZeroish))) {
1514 // => unsigned Int32Cmp
1515 VisitBinop(node, UseInfo::TruncatingWord32(),
1516 MachineRepresentation::kBit);
1517 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1518 return;
1519 }
1520 if ((lhs_type->Is(Type::Signed32()) &&
1521 rhs_type->Is(Type::Signed32())) ||
1522 (lhs_type->Is(Type::Signed32OrMinusZeroOrNaN()) &&
1523 rhs_type->Is(Type::Signed32OrMinusZeroOrNaN()) &&
1524 OneInputCannotBe(node, type_cache_.kZeroish))) {
1525 // => signed Int32Cmp
1526 VisitBinop(node, UseInfo::TruncatingWord32(),
1527 MachineRepresentation::kBit);
1528 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1529 return;
1530 }
1531 // => Float64Cmp
1532 VisitBinop(node, UseInfo::TruncatingFloat64(),
1533 MachineRepresentation::kBit);
1534 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1535 return;
1536 }
1537 case IrOpcode::kNumberLessThan:
1538 case IrOpcode::kNumberLessThanOrEqual: {
1539 // Number comparisons reduce to integer comparisons for integer inputs.
1540 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1541 TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
1542 // => unsigned Int32Cmp
1543 VisitBinop(node, UseInfo::TruncatingWord32(),
1544 MachineRepresentation::kBit);
1545 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1546 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1547 TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
1548 // => signed Int32Cmp
1549 VisitBinop(node, UseInfo::TruncatingWord32(),
1550 MachineRepresentation::kBit);
1551 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1552 } else {
1553 // => Float64Cmp
1554 VisitBinop(node, UseInfo::TruncatingFloat64(),
1555 MachineRepresentation::kBit);
1556 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1557 }
1558 return;
1559 }
1560
1561 case IrOpcode::kSpeculativeNumberAdd:
1562 case IrOpcode::kSpeculativeNumberSubtract:
1563 return VisitSpeculativeAdditiveOp(node, truncation, lowering);
1564
1565 case IrOpcode::kSpeculativeNumberLessThan:
1566 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
1567 case IrOpcode::kSpeculativeNumberEqual: {
1568 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1569 // can only eliminate an unused speculative number operation if we know
1570 // that the inputs are PlainPrimitive, which excludes everything that's
1571 // might have side effects or throws during a ToNumber conversion.
1572 if (BothInputsAre(node, Type::PlainPrimitive())) {
1573 if (truncation.IsUnused()) return VisitUnused(node);
1574 }
1575 // Number comparisons reduce to integer comparisons for integer inputs.
1576 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1577 TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
1578 // => unsigned Int32Cmp
1579 VisitBinop(node, UseInfo::TruncatingWord32(),
1580 MachineRepresentation::kBit);
1581 if (lower()) ChangeToPureOp(node, Uint32Op(node));
1582 return;
1583 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1584 TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
1585 // => signed Int32Cmp
1586 VisitBinop(node, UseInfo::TruncatingWord32(),
1587 MachineRepresentation::kBit);
1588 if (lower()) ChangeToPureOp(node, Int32Op(node));
1589 return;
1590 }
1591 // Try to use type feedback.
1592 NumberOperationHint hint = NumberOperationHintOf(node->op());
1593 switch (hint) {
1594 case NumberOperationHint::kSignedSmall:
1595 case NumberOperationHint::kSigned32: {
1596 if (propagate()) {
1597 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1598 MachineRepresentation::kBit);
1599 } else if (retype()) {
1600 SetOutput(node, MachineRepresentation::kBit, Type::Any());
1601 } else {
1602 DCHECK(lower());
1603 Node* lhs = node->InputAt(0);
1604 Node* rhs = node->InputAt(1);
1605 if (IsNodeRepresentationTagged(lhs) &&
1606 IsNodeRepresentationTagged(rhs)) {
1607 VisitBinop(node, UseInfo::CheckedSignedSmallAsTaggedSigned(),
1608 MachineRepresentation::kBit);
1609 ChangeToPureOp(
1610 node, changer_->TaggedSignedOperatorFor(node->opcode()));
1611
1612 } else {
1613 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1614 MachineRepresentation::kBit);
1615 ChangeToPureOp(node, Int32Op(node));
1616 }
1617 }
1618 return;
1619 }
1620 case NumberOperationHint::kNumberOrOddball:
1621 // Abstract and strict equality don't perform ToNumber conversions
1622 // on Oddballs, so make sure we don't accidentially sneak in a
1623 // hint with Oddball feedback here.
1624 DCHECK_NE(IrOpcode::kSpeculativeNumberEqual, node->opcode());
1625 // Fallthrough
1626 case NumberOperationHint::kNumber:
1627 VisitBinop(node, CheckedUseInfoAsFloat64FromHint(hint),
1628 MachineRepresentation::kBit);
1629 if (lower()) ChangeToPureOp(node, Float64Op(node));
1630 return;
1631 }
1632 UNREACHABLE();
1633 return;
1634 }
1635
1636 case IrOpcode::kNumberAdd:
1637 case IrOpcode::kNumberSubtract: {
1638 if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
1639 (GetUpperBound(node)->Is(Type::Signed32()) ||
1640 GetUpperBound(node)->Is(Type::Unsigned32()) ||
1641 truncation.IsUsedAsWord32())) {
1642 // => Int32Add/Sub
1643 VisitWord32TruncatingBinop(node);
1644 if (lower()) ChangeToPureOp(node, Int32Op(node));
1645 } else {
1646 // => Float64Add/Sub
1647 VisitFloat64Binop(node);
1648 if (lower()) ChangeToPureOp(node, Float64Op(node));
1649 }
1650 return;
1651 }
1652 case IrOpcode::kSpeculativeNumberMultiply: {
1653 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1654 // can only eliminate an unused speculative number operation if we know
1655 // that the inputs are PlainPrimitive, which excludes everything that's
1656 // might have side effects or throws during a ToNumber conversion.
1657 if (BothInputsAre(node, Type::PlainPrimitive())) {
1658 if (truncation.IsUnused()) return VisitUnused(node);
1659 }
1660 if (BothInputsAre(node, Type::Integral32()) &&
1661 (NodeProperties::GetType(node)->Is(Type::Signed32()) ||
1662 NodeProperties::GetType(node)->Is(Type::Unsigned32()) ||
1663 (truncation.IsUsedAsWord32() &&
1664 NodeProperties::GetType(node)->Is(
1665 type_cache_.kSafeIntegerOrMinusZero)))) {
1666 // Multiply reduces to Int32Mul if the inputs are integers, and
1667 // (a) the output is either known to be Signed32, or
1668 // (b) the output is known to be Unsigned32, or
1669 // (c) the uses are truncating and the result is in the safe
1670 // integer range.
1671 VisitWord32TruncatingBinop(node);
1672 if (lower()) ChangeToPureOp(node, Int32Op(node));
1673 return;
1674 }
1675 // Try to use type feedback.
1676 NumberOperationHint hint = NumberOperationHintOf(node->op());
1677 Type* input0_type = TypeOf(node->InputAt(0));
1678 Type* input1_type = TypeOf(node->InputAt(1));
1679
1680 // Handle the case when no int32 checks on inputs are necessary
1681 // (but an overflow check is needed on the output).
1682 if (BothInputsAre(node, Type::Signed32())) {
1683 // If both the inputs the feedback are int32, use the overflow op.
1684 if (hint == NumberOperationHint::kSignedSmall ||
1685 hint == NumberOperationHint::kSigned32) {
1686 VisitBinop(node, UseInfo::TruncatingWord32(),
1687 MachineRepresentation::kWord32, Type::Signed32());
1688 if (lower()) {
1689 LowerToCheckedInt32Mul(node, truncation, input0_type,
1690 input1_type);
1691 }
1692 return;
1693 }
1694 }
1695
1696 if (hint == NumberOperationHint::kSignedSmall ||
1697 hint == NumberOperationHint::kSigned32) {
1698 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1699 MachineRepresentation::kWord32, Type::Signed32());
1700 if (lower()) {
1701 LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type);
1702 }
1703 return;
1704 }
1705
1706 // Checked float64 x float64 => float64
1707 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1708 MachineRepresentation::kFloat64, Type::Number());
1709 if (lower()) ChangeToPureOp(node, Float64Op(node));
1710 return;
1711 }
1712 case IrOpcode::kNumberMultiply: {
1713 if (BothInputsAre(node, Type::Integral32()) &&
1714 (NodeProperties::GetType(node)->Is(Type::Signed32()) ||
1715 NodeProperties::GetType(node)->Is(Type::Unsigned32()) ||
1716 (truncation.IsUsedAsWord32() &&
1717 NodeProperties::GetType(node)->Is(
1718 type_cache_.kSafeIntegerOrMinusZero)))) {
1719 // Multiply reduces to Int32Mul if the inputs are integers, and
1720 // (a) the output is either known to be Signed32, or
1721 // (b) the output is known to be Unsigned32, or
1722 // (c) the uses are truncating and the result is in the safe
1723 // integer range.
1724 VisitWord32TruncatingBinop(node);
1725 if (lower()) ChangeToPureOp(node, Int32Op(node));
1726 return;
1727 }
1728 // Number x Number => Float64Mul
1729 VisitFloat64Binop(node);
1730 if (lower()) ChangeToPureOp(node, Float64Op(node));
1731 return;
1732 }
1733 case IrOpcode::kSpeculativeNumberDivide: {
1734 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1735 // can only eliminate an unused speculative number operation if we know
1736 // that the inputs are PlainPrimitive, which excludes everything that's
1737 // might have side effects or throws during a ToNumber conversion.
1738 if (BothInputsAre(node, Type::PlainPrimitive())) {
1739 if (truncation.IsUnused()) return VisitUnused(node);
1740 }
1741 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
1742 // => unsigned Uint32Div
1743 VisitWord32TruncatingBinop(node);
1744 if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
1745 return;
1746 }
1747 if (BothInputsAreSigned32(node)) {
1748 if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
1749 // => signed Int32Div
1750 VisitWord32TruncatingBinop(node);
1751 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1752 return;
1753 }
1754 if (truncation.IsUsedAsWord32()) {
1755 // => signed Int32Div
1756 VisitWord32TruncatingBinop(node);
1757 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1758 return;
1759 }
1760 }
1761
1762 // Try to use type feedback.
1763 NumberOperationHint hint = NumberOperationHintOf(node->op());
1764
1765 // Handle the case when no uint32 checks on inputs are necessary
1766 // (but an overflow check is needed on the output).
1767 if (BothInputsAreUnsigned32(node)) {
1768 if (hint == NumberOperationHint::kSignedSmall ||
1769 hint == NumberOperationHint::kSigned32) {
1770 VisitBinop(node, UseInfo::TruncatingWord32(),
1771 MachineRepresentation::kWord32, Type::Unsigned32());
1772 if (lower()) ChangeToUint32OverflowOp(node);
1773 return;
1774 }
1775 }
1776
1777 // Handle the case when no int32 checks on inputs are necessary
1778 // (but an overflow check is needed on the output).
1779 if (BothInputsAreSigned32(node)) {
1780 // If both the inputs the feedback are int32, use the overflow op.
1781 if (hint == NumberOperationHint::kSignedSmall ||
1782 hint == NumberOperationHint::kSigned32) {
1783 VisitBinop(node, UseInfo::TruncatingWord32(),
1784 MachineRepresentation::kWord32, Type::Signed32());
1785 if (lower()) ChangeToInt32OverflowOp(node);
1786 return;
1787 }
1788 }
1789
1790 if (hint == NumberOperationHint::kSignedSmall ||
1791 hint == NumberOperationHint::kSigned32) {
1792 // If the result is truncated, we only need to check the inputs.
1793 if (truncation.IsUsedAsWord32()) {
1794 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1795 MachineRepresentation::kWord32);
1796 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1797 } else {
1798 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1799 MachineRepresentation::kWord32, Type::Signed32());
1800 if (lower()) ChangeToInt32OverflowOp(node);
1801 }
1802 return;
1803 }
1804
1805 // default case => Float64Div
1806 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1807 MachineRepresentation::kFloat64, Type::Number());
1808 if (lower()) ChangeToPureOp(node, Float64Op(node));
1809 return;
1810 }
1811 case IrOpcode::kNumberDivide: {
1812 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
1813 // => unsigned Uint32Div
1814 VisitWord32TruncatingBinop(node);
1815 if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
1816 return;
1817 }
1818 if (BothInputsAreSigned32(node)) {
1819 if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
1820 // => signed Int32Div
1821 VisitWord32TruncatingBinop(node);
1822 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1823 return;
1824 }
1825 if (truncation.IsUsedAsWord32()) {
1826 // => signed Int32Div
1827 VisitWord32TruncatingBinop(node);
1828 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1829 return;
1830 }
1831 }
1832 // Number x Number => Float64Div
1833 VisitFloat64Binop(node);
1834 if (lower()) ChangeToPureOp(node, Float64Op(node));
1835 return;
1836 }
1837 case IrOpcode::kSpeculativeNumberModulus:
1838 return VisitSpeculativeNumberModulus(node, truncation, lowering);
1839 case IrOpcode::kNumberModulus: {
1840 if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1841 (truncation.IsUsedAsWord32() ||
1842 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1843 // => unsigned Uint32Mod
1844 VisitWord32TruncatingBinop(node);
1845 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1846 return;
1847 }
1848 if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1849 (truncation.IsUsedAsWord32() ||
1850 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1851 // => signed Int32Mod
1852 VisitWord32TruncatingBinop(node);
1853 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1854 return;
1855 }
1856 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1857 TypeOf(node->InputAt(1))->Is(Type::Unsigned32()) &&
1858 (truncation.IsUsedAsWord32() ||
1859 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1860 // We can only promise Float64 truncation here, as the decision is
1861 // based on the feedback types of the inputs.
1862 VisitBinop(node, UseInfo(MachineRepresentation::kWord32,
1863 Truncation::Float64()),
1864 MachineRepresentation::kWord32);
1865 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1866 return;
1867 }
1868 if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1869 TypeOf(node->InputAt(1))->Is(Type::Signed32()) &&
1870 (truncation.IsUsedAsWord32() ||
1871 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1872 // We can only promise Float64 truncation here, as the decision is
1873 // based on the feedback types of the inputs.
1874 VisitBinop(node, UseInfo(MachineRepresentation::kWord32,
1875 Truncation::Float64()),
1876 MachineRepresentation::kWord32);
1877 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1878 return;
1879 }
1880 // default case => Float64Mod
1881 VisitFloat64Binop(node);
1882 if (lower()) ChangeToPureOp(node, Float64Op(node));
1883 return;
1884 }
1885 case IrOpcode::kNumberBitwiseOr:
1886 case IrOpcode::kNumberBitwiseXor:
1887 case IrOpcode::kNumberBitwiseAnd: {
1888 VisitWord32TruncatingBinop(node);
1889 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1890 return;
1891 }
1892 case IrOpcode::kSpeculativeNumberBitwiseOr:
1893 case IrOpcode::kSpeculativeNumberBitwiseXor:
1894 case IrOpcode::kSpeculativeNumberBitwiseAnd:
1895 VisitSpeculativeInt32Binop(node);
1896 if (lower()) {
1897 ChangeToPureOp(node, Int32Op(node));
1898 }
1899 return;
1900 case IrOpcode::kNumberShiftLeft: {
1901 Type* rhs_type = GetUpperBound(node->InputAt(1));
1902 VisitBinop(node, UseInfo::TruncatingWord32(),
1903 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1904 if (lower()) {
1905 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
1906 }
1907 return;
1908 }
1909 case IrOpcode::kSpeculativeNumberShiftLeft: {
1910 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1911 // can only eliminate an unused speculative number operation if we know
1912 // that the inputs are PlainPrimitive, which excludes everything that's
1913 // might have side effects or throws during a ToNumber conversion.
1914 if (BothInputsAre(node, Type::PlainPrimitive())) {
1915 if (truncation.IsUnused()) return VisitUnused(node);
1916 }
1917 if (BothInputsAre(node, Type::NumberOrOddball())) {
1918 Type* rhs_type = GetUpperBound(node->InputAt(1));
1919 VisitBinop(node, UseInfo::TruncatingWord32(),
1920 UseInfo::TruncatingWord32(),
1921 MachineRepresentation::kWord32);
1922 if (lower()) {
1923 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
1924 }
1925 return;
1926 }
1927 NumberOperationHint hint = NumberOperationHintOf(node->op());
1928 Type* rhs_type = GetUpperBound(node->InputAt(1));
1929 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1930 MachineRepresentation::kWord32, Type::Signed32());
1931 if (lower()) {
1932 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
1933 }
1934 return;
1935 }
1936 case IrOpcode::kNumberShiftRight: {
1937 Type* rhs_type = GetUpperBound(node->InputAt(1));
1938 VisitBinop(node, UseInfo::TruncatingWord32(),
1939 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1940 if (lower()) {
1941 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
1942 }
1943 return;
1944 }
1945 case IrOpcode::kSpeculativeNumberShiftRight: {
1946 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1947 // can only eliminate an unused speculative number operation if we know
1948 // that the inputs are PlainPrimitive, which excludes everything that's
1949 // might have side effects or throws during a ToNumber conversion.
1950 if (BothInputsAre(node, Type::PlainPrimitive())) {
1951 if (truncation.IsUnused()) return VisitUnused(node);
1952 }
1953 if (BothInputsAre(node, Type::NumberOrOddball())) {
1954 Type* rhs_type = GetUpperBound(node->InputAt(1));
1955 VisitBinop(node, UseInfo::TruncatingWord32(),
1956 UseInfo::TruncatingWord32(),
1957 MachineRepresentation::kWord32);
1958 if (lower()) {
1959 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
1960 }
1961 return;
1962 }
1963 NumberOperationHint hint = NumberOperationHintOf(node->op());
1964 Type* rhs_type = GetUpperBound(node->InputAt(1));
1965 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1966 MachineRepresentation::kWord32, Type::Signed32());
1967 if (lower()) {
1968 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
1969 }
1970 return;
1971 }
1972 case IrOpcode::kNumberShiftRightLogical: {
1973 Type* rhs_type = GetUpperBound(node->InputAt(1));
1974 VisitBinop(node, UseInfo::TruncatingWord32(),
1975 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1976 if (lower()) {
1977 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
1978 }
1979 return;
1980 }
1981 case IrOpcode::kSpeculativeNumberShiftRightLogical: {
1982 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1983 // can only eliminate an unused speculative number operation if we know
1984 // that the inputs are PlainPrimitive, which excludes everything that's
1985 // might have side effects or throws during a ToNumber conversion.
1986 if (BothInputsAre(node, Type::PlainPrimitive())) {
1987 if (truncation.IsUnused()) return VisitUnused(node);
1988 }
1989 NumberOperationHint hint = NumberOperationHintOf(node->op());
1990 Type* rhs_type = GetUpperBound(node->InputAt(1));
1991 if (rhs_type->Is(type_cache_.kZeroish) &&
1992 (hint == NumberOperationHint::kSignedSmall ||
1993 hint == NumberOperationHint::kSigned32) &&
1994 !truncation.IsUsedAsWord32()) {
1995 // The SignedSmall or Signed32 feedback means that the results that we
1996 // have seen so far were of type Unsigned31. We speculate that this
1997 // will continue to hold. Moreover, since the RHS is 0, the result
1998 // will just be the (converted) LHS.
1999 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2000 MachineRepresentation::kWord32, Type::Unsigned31());
2001 if (lower()) {
2002 node->RemoveInput(1);
2003 NodeProperties::ChangeOp(node,
2004 simplified()->CheckedUint32ToInt32());
2005 }
2006 return;
2007 }
2008 if (BothInputsAre(node, Type::NumberOrOddball())) {
2009 VisitBinop(node, UseInfo::TruncatingWord32(),
2010 UseInfo::TruncatingWord32(),
2011 MachineRepresentation::kWord32);
2012 if (lower()) {
2013 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
2014 }
2015 return;
2016 }
2017 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2018 MachineRepresentation::kWord32, Type::Unsigned32());
2019 if (lower()) {
2020 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
2021 }
2022 return;
2023 }
2024 case IrOpcode::kNumberAbs: {
2025 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32())) {
2026 VisitUnop(node, UseInfo::TruncatingWord32(),
2027 MachineRepresentation::kWord32);
2028 if (lower()) DeferReplacement(node, node->InputAt(0));
2029 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32())) {
2030 VisitUnop(node, UseInfo::TruncatingWord32(),
2031 MachineRepresentation::kWord32);
2032 if (lower()) DeferReplacement(node, lowering->Int32Abs(node));
2033 } else if (TypeOf(node->InputAt(0))
2034 ->Is(type_cache_.kPositiveIntegerOrMinusZeroOrNaN)) {
2035 VisitUnop(node, UseInfo::TruncatingFloat64(),
2036 MachineRepresentation::kFloat64);
2037 if (lower()) DeferReplacement(node, node->InputAt(0));
2038 } else {
2039 VisitUnop(node, UseInfo::TruncatingFloat64(),
2040 MachineRepresentation::kFloat64);
2041 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2042 }
2043 return;
2044 }
2045 case IrOpcode::kNumberClz32: {
2046 VisitUnop(node, UseInfo::TruncatingWord32(),
2047 MachineRepresentation::kWord32);
2048 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
2049 return;
2050 }
2051 case IrOpcode::kNumberImul: {
2052 VisitBinop(node, UseInfo::TruncatingWord32(),
2053 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2054 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
2055 return;
2056 }
2057 case IrOpcode::kNumberFround: {
2058 VisitUnop(node, UseInfo::TruncatingFloat64(),
2059 MachineRepresentation::kFloat32);
2060 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2061 return;
2062 }
2063 case IrOpcode::kNumberMax: {
2064 // TODO(turbofan): We should consider feedback types here as well.
2065 if (BothInputsAreUnsigned32(node)) {
2066 VisitWord32TruncatingBinop(node);
2067 if (lower()) {
2068 lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
2069 MachineRepresentation::kWord32);
2070 }
2071 } else if (BothInputsAreSigned32(node)) {
2072 VisitWord32TruncatingBinop(node);
2073 if (lower()) {
2074 lowering->DoMax(node, lowering->machine()->Int32LessThan(),
2075 MachineRepresentation::kWord32);
2076 }
2077 } else if (BothInputsAre(node, Type::PlainNumber())) {
2078 VisitFloat64Binop(node);
2079 if (lower()) {
2080 lowering->DoMax(node, lowering->machine()->Float64LessThan(),
2081 MachineRepresentation::kFloat64);
2082 }
2083 } else {
2084 VisitFloat64Binop(node);
2085 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2086 }
2087 return;
2088 }
2089 case IrOpcode::kNumberMin: {
2090 // TODO(turbofan): We should consider feedback types here as well.
2091 if (BothInputsAreUnsigned32(node)) {
2092 VisitWord32TruncatingBinop(node);
2093 if (lower()) {
2094 lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
2095 MachineRepresentation::kWord32);
2096 }
2097 } else if (BothInputsAreSigned32(node)) {
2098 VisitWord32TruncatingBinop(node);
2099 if (lower()) {
2100 lowering->DoMin(node, lowering->machine()->Int32LessThan(),
2101 MachineRepresentation::kWord32);
2102 }
2103 } else if (BothInputsAre(node, Type::PlainNumber())) {
2104 VisitFloat64Binop(node);
2105 if (lower()) {
2106 lowering->DoMin(node, lowering->machine()->Float64LessThan(),
2107 MachineRepresentation::kFloat64);
2108 }
2109 } else {
2110 VisitFloat64Binop(node);
2111 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2112 }
2113 return;
2114 }
2115 case IrOpcode::kNumberAtan2:
2116 case IrOpcode::kNumberPow: {
2117 VisitBinop(node, UseInfo::TruncatingFloat64(),
2118 MachineRepresentation::kFloat64);
2119 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2120 return;
2121 }
2122 case IrOpcode::kNumberAcos:
2123 case IrOpcode::kNumberAcosh:
2124 case IrOpcode::kNumberAsin:
2125 case IrOpcode::kNumberAsinh:
2126 case IrOpcode::kNumberAtan:
2127 case IrOpcode::kNumberAtanh:
2128 case IrOpcode::kNumberCeil:
2129 case IrOpcode::kNumberCos:
2130 case IrOpcode::kNumberCosh:
2131 case IrOpcode::kNumberExp:
2132 case IrOpcode::kNumberExpm1:
2133 case IrOpcode::kNumberFloor:
2134 case IrOpcode::kNumberLog:
2135 case IrOpcode::kNumberLog1p:
2136 case IrOpcode::kNumberLog2:
2137 case IrOpcode::kNumberLog10:
2138 case IrOpcode::kNumberCbrt:
2139 case IrOpcode::kNumberSin:
2140 case IrOpcode::kNumberSinh:
2141 case IrOpcode::kNumberTan:
2142 case IrOpcode::kNumberTanh:
2143 case IrOpcode::kNumberTrunc: {
2144 VisitUnop(node, UseInfo::TruncatingFloat64(),
2145 MachineRepresentation::kFloat64);
2146 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2147 return;
2148 }
2149 case IrOpcode::kNumberRound: {
2150 VisitUnop(node, UseInfo::TruncatingFloat64(),
2151 MachineRepresentation::kFloat64);
2152 if (lower()) DeferReplacement(node, lowering->Float64Round(node));
2153 return;
2154 }
2155 case IrOpcode::kNumberSign: {
2156 if (InputIs(node, Type::Signed32())) {
2157 VisitUnop(node, UseInfo::TruncatingWord32(),
2158 MachineRepresentation::kWord32);
2159 if (lower()) DeferReplacement(node, lowering->Int32Sign(node));
2160 } else {
2161 VisitUnop(node, UseInfo::TruncatingFloat64(),
2162 MachineRepresentation::kFloat64);
2163 if (lower()) DeferReplacement(node, lowering->Float64Sign(node));
2164 }
2165 return;
2166 }
2167 case IrOpcode::kNumberSqrt: {
2168 VisitUnop(node, UseInfo::TruncatingFloat64(),
2169 MachineRepresentation::kFloat64);
2170 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2171 return;
2172 }
2173 case IrOpcode::kNumberToBoolean: {
2174 Type* const input_type = TypeOf(node->InputAt(0));
2175 if (input_type->Is(Type::Integral32())) {
2176 VisitUnop(node, UseInfo::TruncatingWord32(),
2177 MachineRepresentation::kBit);
2178 if (lower()) lowering->DoIntegral32ToBit(node);
2179 } else if (input_type->Is(Type::OrderedNumber())) {
2180 VisitUnop(node, UseInfo::TruncatingFloat64(),
2181 MachineRepresentation::kBit);
2182 if (lower()) lowering->DoOrderedNumberToBit(node);
2183 } else {
2184 VisitUnop(node, UseInfo::TruncatingFloat64(),
2185 MachineRepresentation::kBit);
2186 if (lower()) lowering->DoNumberToBit(node);
2187 }
2188 return;
2189 }
2190 case IrOpcode::kNumberToInt32: {
2191 // Just change representation if necessary.
2192 VisitUnop(node, UseInfo::TruncatingWord32(),
2193 MachineRepresentation::kWord32);
2194 if (lower()) DeferReplacement(node, node->InputAt(0));
2195 return;
2196 }
2197 case IrOpcode::kNumberToUint32: {
2198 // Just change representation if necessary.
2199 VisitUnop(node, UseInfo::TruncatingWord32(),
2200 MachineRepresentation::kWord32);
2201 if (lower()) DeferReplacement(node, node->InputAt(0));
2202 return;
2203 }
2204 case IrOpcode::kNumberToUint8Clamped: {
2205 Type* const input_type = TypeOf(node->InputAt(0));
2206 if (input_type->Is(type_cache_.kUint8OrMinusZeroOrNaN)) {
2207 VisitUnop(node, UseInfo::TruncatingWord32(),
2208 MachineRepresentation::kWord32);
2209 if (lower()) DeferReplacement(node, node->InputAt(0));
2210 } else if (input_type->Is(Type::Unsigned32OrMinusZeroOrNaN())) {
2211 VisitUnop(node, UseInfo::TruncatingWord32(),
2212 MachineRepresentation::kWord32);
2213 if (lower()) lowering->DoUnsigned32ToUint8Clamped(node);
2214 } else if (input_type->Is(Type::Signed32OrMinusZeroOrNaN())) {
2215 VisitUnop(node, UseInfo::TruncatingWord32(),
2216 MachineRepresentation::kWord32);
2217 if (lower()) lowering->DoSigned32ToUint8Clamped(node);
2218 } else if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
2219 VisitUnop(node, UseInfo::TruncatingFloat64(),
2220 MachineRepresentation::kFloat64);
2221 if (lower()) lowering->DoIntegerToUint8Clamped(node);
2222 } else {
2223 VisitUnop(node, UseInfo::TruncatingFloat64(),
2224 MachineRepresentation::kFloat64);
2225 if (lower()) lowering->DoNumberToUint8Clamped(node);
2226 }
2227 return;
2228 }
2229 case IrOpcode::kReferenceEqual: {
2230 VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2231 if (lower()) {
2232 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
2233 }
2234 return;
2235 }
2236 case IrOpcode::kStringEqual:
2237 case IrOpcode::kStringLessThan:
2238 case IrOpcode::kStringLessThanOrEqual: {
2239 return VisitBinop(node, UseInfo::AnyTagged(),
2240 MachineRepresentation::kTaggedPointer);
2241 }
2242 case IrOpcode::kStringCharAt: {
2243 VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
2244 MachineRepresentation::kTaggedPointer);
2245 return;
2246 }
2247 case IrOpcode::kStringCharCodeAt: {
2248 // TODO(turbofan): Allow builtins to return untagged values.
2249 VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
2250 MachineRepresentation::kTaggedSigned);
2251 return;
2252 }
2253 case IrOpcode::kStringFromCharCode: {
2254 VisitUnop(node, UseInfo::TruncatingWord32(),
2255 MachineRepresentation::kTaggedPointer);
2256 return;
2257 }
2258 case IrOpcode::kStringFromCodePoint: {
2259 VisitUnop(node, UseInfo::TruncatingWord32(),
2260 MachineRepresentation::kTaggedPointer);
2261 return;
2262 }
2263 case IrOpcode::kStringIndexOf: {
2264 ProcessInput(node, 0, UseInfo::AnyTagged());
2265 ProcessInput(node, 1, UseInfo::AnyTagged());
2266 ProcessInput(node, 2, UseInfo::TaggedSigned());
2267 SetOutput(node, MachineRepresentation::kTaggedSigned);
2268 return;
2269 }
2270
2271 case IrOpcode::kCheckBounds: {
2272 Type* index_type = TypeOf(node->InputAt(0));
2273 Type* length_type = TypeOf(node->InputAt(1));
2274 if (index_type->Is(Type::Unsigned32())) {
2275 VisitBinop(node, UseInfo::TruncatingWord32(),
2276 MachineRepresentation::kWord32);
2277 if (lower() && index_type->Max() < length_type->Min()) {
2278 // The bounds check is redundant if we already know that
2279 // the index is within the bounds of [0.0, length[.
2280 DeferReplacement(node, node->InputAt(0));
2281 }
2282 } else {
2283 VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
2284 UseInfo::TruncatingWord32(),
2285 MachineRepresentation::kWord32);
2286 }
2287 return;
2288 }
2289 case IrOpcode::kCheckHeapObject: {
2290 if (InputCannotBe(node, Type::SignedSmall())) {
2291 VisitUnop(node, UseInfo::AnyTagged(),
2292 MachineRepresentation::kTaggedPointer);
2293 } else {
2294 VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
2295 MachineRepresentation::kTaggedPointer);
2296 }
2297 if (lower()) DeferReplacement(node, node->InputAt(0));
2298 return;
2299 }
2300 case IrOpcode::kCheckIf: {
2301 ProcessInput(node, 0, UseInfo::Bool());
2302 ProcessRemainingInputs(node, 1);
2303 SetOutput(node, MachineRepresentation::kNone);
2304 return;
2305 }
2306 case IrOpcode::kCheckInternalizedString: {
2307 if (InputIs(node, Type::InternalizedString())) {
2308 VisitUnop(node, UseInfo::AnyTagged(),
2309 MachineRepresentation::kTaggedPointer);
2310 if (lower()) DeferReplacement(node, node->InputAt(0));
2311 } else {
2312 VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
2313 MachineRepresentation::kTaggedPointer);
2314 }
2315 return;
2316 }
2317 case IrOpcode::kCheckNumber: {
2318 if (InputIs(node, Type::Number())) {
2319 if (truncation.IsUsedAsWord32()) {
2320 VisitUnop(node, UseInfo::TruncatingWord32(),
2321 MachineRepresentation::kWord32);
2322 } else {
2323 // TODO(jarin,bmeurer): We need to go to Tagged here, because
2324 // otherwise we cannot distinguish the hole NaN (which might need to
2325 // be treated as undefined). We should have a dedicated Type for
2326 // that at some point, and maybe even a dedicated truncation.
2327 VisitUnop(node, UseInfo::AnyTagged(),
2328 MachineRepresentation::kTagged);
2329 }
2330 if (lower()) DeferReplacement(node, node->InputAt(0));
2331 } else {
2332 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2333 }
2334 return;
2335 }
2336 case IrOpcode::kCheckReceiver: {
2337 if (InputIs(node, Type::Receiver())) {
2338 VisitUnop(node, UseInfo::AnyTagged(),
2339 MachineRepresentation::kTaggedPointer);
2340 if (lower()) DeferReplacement(node, node->InputAt(0));
2341 } else {
2342 VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
2343 MachineRepresentation::kTaggedPointer);
2344 }
2345 return;
2346 }
2347 case IrOpcode::kCheckSmi: {
2348 if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
2349 VisitUnop(node, UseInfo::CheckedSignedSmallAsWord32(),
2350 MachineRepresentation::kWord32);
2351 } else {
2352 VisitUnop(node, UseInfo::CheckedSignedSmallAsTaggedSigned(),
2353 MachineRepresentation::kTaggedSigned);
2354 }
2355 if (lower()) DeferReplacement(node, node->InputAt(0));
2356 return;
2357 }
2358 case IrOpcode::kCheckString: {
2359 if (InputIs(node, Type::String())) {
2360 VisitUnop(node, UseInfo::AnyTagged(),
2361 MachineRepresentation::kTaggedPointer);
2362 if (lower()) DeferReplacement(node, node->InputAt(0));
2363 } else {
2364 VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
2365 MachineRepresentation::kTaggedPointer);
2366 }
2367 return;
2368 }
2369
2370 case IrOpcode::kAllocate: {
2371 ProcessInput(node, 0, UseInfo::TruncatingWord32());
2372 ProcessRemainingInputs(node, 1);
2373 SetOutput(node, MachineRepresentation::kTaggedPointer);
2374 return;
2375 }
2376 case IrOpcode::kLoadField: {
2377 if (truncation.IsUnused()) return VisitUnused(node);
2378 FieldAccess access = FieldAccessOf(node->op());
2379 MachineRepresentation const representation =
2380 access.machine_type.representation();
2381 VisitUnop(node, UseInfoForBasePointer(access), representation);
2382 return;
2383 }
2384 case IrOpcode::kStoreField: {
2385 FieldAccess access = FieldAccessOf(node->op());
2386 NodeInfo* input_info = GetInfo(node->InputAt(1));
2387 WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2388 access.base_is_tagged, access.machine_type.representation(),
2389 access.offset, access.type, input_info->representation(),
2390 node->InputAt(1));
2391 ProcessInput(node, 0, UseInfoForBasePointer(access));
2392 ProcessInput(node, 1, TruncatingUseInfoFromRepresentation(
2393 access.machine_type.representation()));
2394 ProcessRemainingInputs(node, 2);
2395 SetOutput(node, MachineRepresentation::kNone);
2396 if (lower()) {
2397 if (write_barrier_kind < access.write_barrier_kind) {
2398 access.write_barrier_kind = write_barrier_kind;
2399 NodeProperties::ChangeOp(
2400 node, jsgraph_->simplified()->StoreField(access));
2401 }
2402 }
2403 return;
2404 }
2405 case IrOpcode::kLoadBuffer: {
2406 if (truncation.IsUnused()) return VisitUnused(node);
2407 BufferAccess access = BufferAccessOf(node->op());
2408 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
2409 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
2410 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
2411 ProcessRemainingInputs(node, 3);
2412
2413 MachineRepresentation output;
2414 if (truncation.IdentifiesUndefinedAndNaNAndZero()) {
2415 if (truncation.IdentifiesNaNAndZero()) {
2416 // If undefined is truncated to a non-NaN number, we can use
2417 // the load's representation.
2418 output = access.machine_type().representation();
2419 } else {
2420 // If undefined is truncated to a number, but the use can
2421 // observe NaN, we need to output at least the float32
2422 // representation.
2423 if (access.machine_type().representation() ==
2424 MachineRepresentation::kFloat32) {
2425 output = access.machine_type().representation();
2426 } else {
2427 output = MachineRepresentation::kFloat64;
2428 }
2429 }
2430 } else {
2431 // If undefined is not truncated away, we need to have the tagged
2432 // representation.
2433 output = MachineRepresentation::kTagged;
2434 }
2435 SetOutput(node, output);
2436 if (lower()) lowering->DoLoadBuffer(node, output, changer_);
2437 return;
2438 }
2439 case IrOpcode::kStoreBuffer: {
2440 BufferAccess access = BufferAccessOf(node->op());
2441 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
2442 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
2443 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
2444 ProcessInput(node, 3,
2445 TruncatingUseInfoFromRepresentation(
2446 access.machine_type().representation())); // value
2447 ProcessRemainingInputs(node, 4);
2448 SetOutput(node, MachineRepresentation::kNone);
2449 if (lower()) lowering->DoStoreBuffer(node);
2450 return;
2451 }
2452 case IrOpcode::kLoadElement: {
2453 if (truncation.IsUnused()) return VisitUnused(node);
2454 ElementAccess access = ElementAccessOf(node->op());
2455 VisitBinop(node, UseInfoForBasePointer(access),
2456 UseInfo::TruncatingWord32(),
2457 access.machine_type.representation());
2458 return;
2459 }
2460 case IrOpcode::kStoreElement: {
2461 ElementAccess access = ElementAccessOf(node->op());
2462 NodeInfo* input_info = GetInfo(node->InputAt(2));
2463 WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2464 access.base_is_tagged, access.machine_type.representation(),
2465 access.type, input_info->representation(), node->InputAt(2));
2466 ProcessInput(node, 0, UseInfoForBasePointer(access)); // base
2467 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
2468 ProcessInput(node, 2,
2469 TruncatingUseInfoFromRepresentation(
2470 access.machine_type.representation())); // value
2471 ProcessRemainingInputs(node, 3);
2472 SetOutput(node, MachineRepresentation::kNone);
2473 if (lower()) {
2474 if (write_barrier_kind < access.write_barrier_kind) {
2475 access.write_barrier_kind = write_barrier_kind;
2476 NodeProperties::ChangeOp(
2477 node, jsgraph_->simplified()->StoreElement(access));
2478 }
2479 }
2480 return;
2481 }
2482 case IrOpcode::kLoadTypedElement: {
2483 MachineRepresentation const rep =
2484 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2485 ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2486 ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2487 ProcessInput(node, 2, UseInfo::PointerInt()); // external pointer
2488 ProcessInput(node, 3, UseInfo::TruncatingWord32()); // index
2489 ProcessRemainingInputs(node, 4);
2490 SetOutput(node, rep);
2491 return;
2492 }
2493 case IrOpcode::kStoreTypedElement: {
2494 MachineRepresentation const rep =
2495 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2496 ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2497 ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2498 ProcessInput(node, 2, UseInfo::PointerInt()); // external pointer
2499 ProcessInput(node, 3, UseInfo::TruncatingWord32()); // index
2500 ProcessInput(node, 4,
2501 TruncatingUseInfoFromRepresentation(rep)); // value
2502 ProcessRemainingInputs(node, 5);
2503 SetOutput(node, MachineRepresentation::kNone);
2504 return;
2505 }
2506 case IrOpcode::kPlainPrimitiveToNumber: {
2507 if (InputIs(node, Type::Boolean())) {
2508 VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32);
2509 if (lower()) DeferReplacement(node, node->InputAt(0));
2510 } else if (InputIs(node, Type::String())) {
2511 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2512 if (lower()) lowering->DoStringToNumber(node);
2513 } else if (truncation.IsUsedAsWord32()) {
2514 if (InputIs(node, Type::NumberOrOddball())) {
2515 VisitUnop(node, UseInfo::TruncatingWord32(),
2516 MachineRepresentation::kWord32);
2517 if (lower()) DeferReplacement(node, node->InputAt(0));
2518 } else {
2519 VisitUnop(node, UseInfo::AnyTagged(),
2520 MachineRepresentation::kWord32);
2521 if (lower()) {
2522 NodeProperties::ChangeOp(node,
2523 simplified()->PlainPrimitiveToWord32());
2524 }
2525 }
2526 } else if (truncation.IsUsedAsFloat64()) {
2527 if (InputIs(node, Type::NumberOrOddball())) {
2528 VisitUnop(node, UseInfo::TruncatingFloat64(),
2529 MachineRepresentation::kFloat64);
2530 if (lower()) DeferReplacement(node, node->InputAt(0));
2531 } else {
2532 VisitUnop(node, UseInfo::AnyTagged(),
2533 MachineRepresentation::kFloat64);
2534 if (lower()) {
2535 NodeProperties::ChangeOp(node,
2536 simplified()->PlainPrimitiveToFloat64());
2537 }
2538 }
2539 } else {
2540 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2541 }
2542 return;
2543 }
2544 case IrOpcode::kObjectIsDetectableCallable: {
2545 VisitObjectIs(node, Type::DetectableCallable(), lowering);
2546 return;
2547 }
2548 case IrOpcode::kObjectIsNonCallable: {
2549 VisitObjectIs(node, Type::NonCallable(), lowering);
2550 return;
2551 }
2552 case IrOpcode::kObjectIsNumber: {
2553 VisitObjectIs(node, Type::Number(), lowering);
2554 return;
2555 }
2556 case IrOpcode::kObjectIsReceiver: {
2557 VisitObjectIs(node, Type::Receiver(), lowering);
2558 return;
2559 }
2560 case IrOpcode::kObjectIsSmi: {
2561 // TODO(turbofan): Optimize based on input representation.
2562 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2563 return;
2564 }
2565 case IrOpcode::kObjectIsString: {
2566 VisitObjectIs(node, Type::String(), lowering);
2567 return;
2568 }
2569 case IrOpcode::kObjectIsUndetectable: {
2570 VisitObjectIs(node, Type::Undetectable(), lowering);
2571 return;
2572 }
2573 case IrOpcode::kNewRestParameterElements:
2574 case IrOpcode::kNewUnmappedArgumentsElements: {
2575 ProcessRemainingInputs(node, 0);
2576 SetOutput(node, MachineRepresentation::kTaggedPointer);
2577 return;
2578 }
2579 case IrOpcode::kArrayBufferWasNeutered: {
2580 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2581 return;
2582 }
2583 case IrOpcode::kCheckFloat64Hole: {
2584 CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op());
2585 ProcessInput(node, 0, UseInfo::TruncatingFloat64());
2586 ProcessRemainingInputs(node, 1);
2587 SetOutput(node, MachineRepresentation::kFloat64);
2588 if (truncation.IsUsedAsFloat64() &&
2589 mode == CheckFloat64HoleMode::kAllowReturnHole) {
2590 if (lower()) DeferReplacement(node, node->InputAt(0));
2591 }
2592 return;
2593 }
2594 case IrOpcode::kCheckTaggedHole: {
2595 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2596 return;
2597 }
2598 case IrOpcode::kConvertTaggedHoleToUndefined: {
2599 if (InputIs(node, Type::NumberOrOddball()) &&
2600 truncation.IsUsedAsWord32()) {
2601 // Propagate the Word32 truncation.
2602 VisitUnop(node, UseInfo::TruncatingWord32(),
2603 MachineRepresentation::kWord32);
2604 if (lower()) DeferReplacement(node, node->InputAt(0));
2605 } else if (InputIs(node, Type::NumberOrOddball()) &&
2606 truncation.IsUsedAsFloat64()) {
2607 // Propagate the Float64 truncation.
2608 VisitUnop(node, UseInfo::TruncatingFloat64(),
2609 MachineRepresentation::kFloat64);
2610 if (lower()) DeferReplacement(node, node->InputAt(0));
2611 } else if (InputIs(node, Type::NonInternal())) {
2612 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2613 if (lower()) DeferReplacement(node, node->InputAt(0));
2614 } else {
2615 // TODO(turbofan): Add a (Tagged) truncation that identifies hole
2616 // and undefined, i.e. for a[i] === obj cases.
2617 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2618 }
2619 return;
2620 }
2621 case IrOpcode::kCheckMaps:
2622 case IrOpcode::kTransitionElementsKind: {
2623 VisitInputs(node);
2624 return SetOutput(node, MachineRepresentation::kNone);
2625 }
2626 case IrOpcode::kEnsureWritableFastElements:
2627 return VisitBinop(node, UseInfo::AnyTagged(),
2628 MachineRepresentation::kTaggedPointer);
2629 case IrOpcode::kMaybeGrowFastElements: {
2630 ProcessInput(node, 0, UseInfo::AnyTagged()); // object
2631 ProcessInput(node, 1, UseInfo::AnyTagged()); // elements
2632 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // index
2633 ProcessInput(node, 3, UseInfo::TruncatingWord32()); // length
2634 ProcessRemainingInputs(node, 4);
2635 SetOutput(node, MachineRepresentation::kTaggedPointer);
2636 return;
2637 }
2638
2639 case IrOpcode::kNumberSilenceNaN:
2640 VisitUnop(node, UseInfo::TruncatingFloat64(),
2641 MachineRepresentation::kFloat64);
2642 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2643 return;
2644 case IrOpcode::kStateValues:
2645 return VisitStateValues(node);
2646 case IrOpcode::kObjectState:
2647 return VisitObjectState(node);
2648 case IrOpcode::kTypeGuard: {
2649 // We just get rid of the sigma here. In principle, it should be
2650 // possible to refine the truncation and representation based on
2651 // the sigma's type.
2652 MachineRepresentation output =
2653 GetOutputInfoForPhi(node, TypeOf(node->InputAt(0)), truncation);
2654 VisitUnop(node, UseInfo(output, truncation), output);
2655 if (lower()) DeferReplacement(node, node->InputAt(0));
2656 return;
2657 }
2658
2659 case IrOpcode::kOsrGuard:
2660 return VisitOsrGuard(node);
2661
2662 case IrOpcode::kFinishRegion:
2663 VisitInputs(node);
2664 // Assume the output is tagged pointer.
2665 return SetOutput(node, MachineRepresentation::kTaggedPointer);
2666
2667 case IrOpcode::kReturn:
2668 VisitReturn(node);
2669 // Assume the output is tagged.
2670 return SetOutput(node, MachineRepresentation::kTagged);
2671
2672 // Operators with all inputs tagged and no or tagged output have uniform
2673 // handling.
2674 case IrOpcode::kEnd:
2675 case IrOpcode::kIfSuccess:
2676 case IrOpcode::kIfException:
2677 case IrOpcode::kIfTrue:
2678 case IrOpcode::kIfFalse:
2679 case IrOpcode::kDeoptimize:
2680 case IrOpcode::kEffectPhi:
2681 case IrOpcode::kTerminate:
2682 case IrOpcode::kFrameState:
2683 case IrOpcode::kCheckpoint:
2684 case IrOpcode::kLoop:
2685 case IrOpcode::kMerge:
2686 case IrOpcode::kThrow:
2687 case IrOpcode::kBeginRegion:
2688 case IrOpcode::kProjection:
2689 case IrOpcode::kOsrValue:
2690 case IrOpcode::kArgumentsObjectState:
2691 // All JavaScript operators except JSToNumber have uniform handling.
2692 #define OPCODE_CASE(name) case IrOpcode::k##name:
2693 JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
2694 JS_OTHER_UNOP_LIST(OPCODE_CASE)
2695 JS_OBJECT_OP_LIST(OPCODE_CASE)
2696 JS_CONTEXT_OP_LIST(OPCODE_CASE)
2697 JS_OTHER_OP_LIST(OPCODE_CASE)
2698 #undef OPCODE_CASE
2699 case IrOpcode::kJSToInteger:
2700 case IrOpcode::kJSToLength:
2701 case IrOpcode::kJSToName:
2702 case IrOpcode::kJSToObject:
2703 case IrOpcode::kJSToString:
2704 VisitInputs(node);
2705 // Assume the output is tagged.
2706 return SetOutput(node, MachineRepresentation::kTagged);
2707
2708 default:
2709 V8_Fatal(
2710 __FILE__, __LINE__,
2711 "Representation inference: unsupported opcode %i (%s), node #%i\n.",
2712 node->opcode(), node->op()->mnemonic(), node->id());
2713 break;
2714 }
2715 UNREACHABLE();
2716 }
2717
DeferReplacement(Node * node,Node * replacement)2718 void DeferReplacement(Node* node, Node* replacement) {
2719 TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
2720 node->op()->mnemonic(), replacement->id(),
2721 replacement->op()->mnemonic());
2722
2723 // Disconnect the node from effect and control chains, if necessary.
2724 if (node->op()->EffectInputCount() > 0) {
2725 DCHECK_LT(0, node->op()->ControlInputCount());
2726 // Disconnect the node from effect and control chains.
2727 Node* control = NodeProperties::GetControlInput(node);
2728 Node* effect = NodeProperties::GetEffectInput(node);
2729 ReplaceEffectControlUses(node, effect, control);
2730 }
2731
2732 replacements_.push_back(node);
2733 replacements_.push_back(replacement);
2734
2735 node->NullAllInputs(); // Node is now dead.
2736 }
2737
Kill(Node * node)2738 void Kill(Node* node) {
2739 TRACE("killing #%d:%s\n", node->id(), node->op()->mnemonic());
2740
2741 if (node->op()->EffectInputCount() == 1) {
2742 DCHECK_LT(0, node->op()->ControlInputCount());
2743 // Disconnect the node from effect and control chains.
2744 Node* control = NodeProperties::GetControlInput(node);
2745 Node* effect = NodeProperties::GetEffectInput(node);
2746 ReplaceEffectControlUses(node, effect, control);
2747 } else {
2748 DCHECK_EQ(0, node->op()->EffectInputCount());
2749 DCHECK_EQ(0, node->op()->ControlOutputCount());
2750 DCHECK_EQ(0, node->op()->EffectOutputCount());
2751 }
2752
2753 node->ReplaceUses(jsgraph_->Dead());
2754
2755 node->NullAllInputs(); // The {node} is now dead.
2756 }
2757
PrintOutputInfo(NodeInfo * info)2758 void PrintOutputInfo(NodeInfo* info) {
2759 if (FLAG_trace_representation) {
2760 OFStream os(stdout);
2761 os << info->representation();
2762 }
2763 }
2764
PrintRepresentation(MachineRepresentation rep)2765 void PrintRepresentation(MachineRepresentation rep) {
2766 if (FLAG_trace_representation) {
2767 OFStream os(stdout);
2768 os << rep;
2769 }
2770 }
2771
PrintTruncation(Truncation truncation)2772 void PrintTruncation(Truncation truncation) {
2773 if (FLAG_trace_representation) {
2774 OFStream os(stdout);
2775 os << truncation.description() << std::endl;
2776 }
2777 }
2778
PrintUseInfo(UseInfo info)2779 void PrintUseInfo(UseInfo info) {
2780 if (FLAG_trace_representation) {
2781 OFStream os(stdout);
2782 os << info.representation() << ":" << info.truncation().description();
2783 }
2784 }
2785
2786 private:
2787 JSGraph* jsgraph_;
2788 Zone* zone_; // Temporary zone.
2789 size_t const count_; // number of nodes in the graph
2790 ZoneVector<NodeInfo> info_; // node id -> usage information
2791 #ifdef DEBUG
2792 ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
2793 // requirements on inputs.
2794 #endif // DEBUG
2795 NodeVector nodes_; // collected nodes
2796 NodeVector replacements_; // replacements to be done after lowering
2797 Phase phase_; // current phase of algorithm
2798 RepresentationChanger* changer_; // for inserting representation changes
2799 ZoneQueue<Node*> queue_; // queue for traversing the graph
2800
2801 struct NodeState {
2802 Node* node;
2803 int input_index;
2804 };
2805 ZoneStack<NodeState> typing_stack_; // stack for graph typing.
2806 // TODO(danno): RepresentationSelector shouldn't know anything about the
2807 // source positions table, but must for now since there currently is no other
2808 // way to pass down source position information to nodes created during
2809 // lowering. Once this phase becomes a vanilla reducer, it should get source
2810 // position information via the SourcePositionWrapper like all other reducers.
2811 SourcePositionTable* source_positions_;
2812 TypeCache const& type_cache_;
2813 OperationTyper op_typer_; // helper for the feedback typer
2814
GetInfo(Node * node)2815 NodeInfo* GetInfo(Node* node) {
2816 DCHECK(node->id() < count_);
2817 return &info_[node->id()];
2818 }
zone()2819 Zone* zone() { return zone_; }
graph_zone()2820 Zone* graph_zone() { return jsgraph_->zone(); }
2821 };
2822
SimplifiedLowering(JSGraph * jsgraph,Zone * zone,SourcePositionTable * source_positions)2823 SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
2824 SourcePositionTable* source_positions)
2825 : jsgraph_(jsgraph),
2826 zone_(zone),
2827 type_cache_(TypeCache::Get()),
2828 source_positions_(source_positions) {}
2829
LowerAllNodes()2830 void SimplifiedLowering::LowerAllNodes() {
2831 RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
2832 RepresentationSelector selector(jsgraph(), zone_, &changer,
2833 source_positions_);
2834 selector.Run(this);
2835 }
2836
DoJSToNumberTruncatesToFloat64(Node * node,RepresentationSelector * selector)2837 void SimplifiedLowering::DoJSToNumberTruncatesToFloat64(
2838 Node* node, RepresentationSelector* selector) {
2839 DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode());
2840 Node* value = node->InputAt(0);
2841 Node* context = node->InputAt(1);
2842 Node* frame_state = node->InputAt(2);
2843 Node* effect = node->InputAt(3);
2844 Node* control = node->InputAt(4);
2845 Node* throwing;
2846
2847 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2848 Node* branch0 =
2849 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2850
2851 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2852 Node* etrue0 = effect;
2853 Node* vtrue0;
2854 {
2855 vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
2856 vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
2857 }
2858
2859 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2860 Node* efalse0 = effect;
2861 Node* vfalse0;
2862 {
2863 throwing = vfalse0 = efalse0 =
2864 graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context,
2865 frame_state, efalse0, if_false0);
2866 if_false0 = graph()->NewNode(common()->IfSuccess(), throwing);
2867
2868 Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
2869 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
2870
2871 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2872 Node* etrue1 = efalse0;
2873 Node* vtrue1;
2874 {
2875 vtrue1 =
2876 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
2877 vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
2878 }
2879
2880 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2881 Node* efalse1 = efalse0;
2882 Node* vfalse1;
2883 {
2884 vfalse1 = efalse1 = graph()->NewNode(
2885 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
2886 efalse1, if_false1);
2887 }
2888
2889 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2890 efalse0 =
2891 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
2892 vfalse0 =
2893 graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
2894 vtrue1, vfalse1, if_false0);
2895 }
2896
2897 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2898 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2899 value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
2900 vtrue0, vfalse0, control);
2901
2902 // Replace effect and control uses appropriately.
2903 for (Edge edge : node->use_edges()) {
2904 if (NodeProperties::IsControlEdge(edge)) {
2905 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
2906 edge.from()->ReplaceUses(control);
2907 edge.from()->Kill();
2908 } else if (edge.from()->opcode() == IrOpcode::kIfException) {
2909 edge.UpdateTo(throwing);
2910 } else {
2911 UNREACHABLE();
2912 }
2913 } else if (NodeProperties::IsEffectEdge(edge)) {
2914 edge.UpdateTo(effect);
2915 }
2916 }
2917
2918 selector->DeferReplacement(node, value);
2919 }
2920
DoJSToNumberTruncatesToWord32(Node * node,RepresentationSelector * selector)2921 void SimplifiedLowering::DoJSToNumberTruncatesToWord32(
2922 Node* node, RepresentationSelector* selector) {
2923 DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode());
2924 Node* value = node->InputAt(0);
2925 Node* context = node->InputAt(1);
2926 Node* frame_state = node->InputAt(2);
2927 Node* effect = node->InputAt(3);
2928 Node* control = node->InputAt(4);
2929 Node* throwing;
2930
2931 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2932 Node* branch0 =
2933 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2934
2935 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2936 Node* etrue0 = effect;
2937 Node* vtrue0 =
2938 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
2939
2940 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2941 Node* efalse0 = effect;
2942 Node* vfalse0;
2943 {
2944 throwing = vfalse0 = efalse0 =
2945 graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context,
2946 frame_state, efalse0, if_false0);
2947 if_false0 = graph()->NewNode(common()->IfSuccess(), throwing);
2948
2949 Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
2950 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
2951
2952 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2953 Node* etrue1 = efalse0;
2954 Node* vtrue1 =
2955 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
2956
2957 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2958 Node* efalse1 = efalse0;
2959 Node* vfalse1;
2960 {
2961 vfalse1 = efalse1 = graph()->NewNode(
2962 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
2963 efalse1, if_false1);
2964 vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
2965 }
2966
2967 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2968 efalse0 =
2969 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
2970 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2971 vtrue1, vfalse1, if_false0);
2972 }
2973
2974 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2975 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2976 value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2977 vtrue0, vfalse0, control);
2978
2979 // Replace effect and control uses appropriately.
2980 for (Edge edge : node->use_edges()) {
2981 if (NodeProperties::IsControlEdge(edge)) {
2982 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
2983 edge.from()->ReplaceUses(control);
2984 edge.from()->Kill();
2985 } else if (edge.from()->opcode() == IrOpcode::kIfException) {
2986 edge.UpdateTo(throwing);
2987 } else {
2988 UNREACHABLE();
2989 }
2990 } else if (NodeProperties::IsEffectEdge(edge)) {
2991 edge.UpdateTo(effect);
2992 }
2993 }
2994
2995 selector->DeferReplacement(node, value);
2996 }
2997
DoLoadBuffer(Node * node,MachineRepresentation output_rep,RepresentationChanger * changer)2998 void SimplifiedLowering::DoLoadBuffer(Node* node,
2999 MachineRepresentation output_rep,
3000 RepresentationChanger* changer) {
3001 DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
3002 DCHECK_NE(MachineRepresentation::kNone, output_rep);
3003 MachineType const access_type = BufferAccessOf(node->op()).machine_type();
3004 if (output_rep != access_type.representation()) {
3005 Node* const buffer = node->InputAt(0);
3006 Node* const offset = node->InputAt(1);
3007 Node* const length = node->InputAt(2);
3008 Node* const effect = node->InputAt(3);
3009 Node* const control = node->InputAt(4);
3010 Node* const index =
3011 machine()->Is64()
3012 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset)
3013 : offset;
3014
3015 Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
3016 Node* branch =
3017 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
3018
3019 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
3020 Node* etrue = graph()->NewNode(machine()->Load(access_type), buffer, index,
3021 effect, if_true);
3022 Type* element_type =
3023 Type::Intersect(NodeProperties::GetType(node), Type::Number(), zone());
3024 Node* vtrue = changer->GetRepresentationFor(
3025 etrue, access_type.representation(), element_type, node,
3026 UseInfo(output_rep, Truncation::None()));
3027
3028 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
3029 Node* efalse = effect;
3030 Node* vfalse;
3031 if (output_rep == MachineRepresentation::kTagged) {
3032 vfalse = jsgraph()->UndefinedConstant();
3033 } else if (output_rep == MachineRepresentation::kFloat64) {
3034 vfalse =
3035 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
3036 } else if (output_rep == MachineRepresentation::kFloat32) {
3037 vfalse =
3038 jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
3039 } else {
3040 vfalse = jsgraph()->Int32Constant(0);
3041 }
3042
3043 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
3044 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
3045
3046 // Replace effect uses of {node} with the {ephi}.
3047 NodeProperties::ReplaceUses(node, node, ephi);
3048
3049 // Turn the {node} into a Phi.
3050 node->ReplaceInput(0, vtrue);
3051 node->ReplaceInput(1, vfalse);
3052 node->ReplaceInput(2, merge);
3053 node->TrimInputCount(3);
3054 NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2));
3055 } else {
3056 NodeProperties::ChangeOp(node, machine()->CheckedLoad(access_type));
3057 }
3058 }
3059
3060
DoStoreBuffer(Node * node)3061 void SimplifiedLowering::DoStoreBuffer(Node* node) {
3062 DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
3063 MachineRepresentation const rep =
3064 BufferAccessOf(node->op()).machine_type().representation();
3065 NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
3066 }
3067
Float64Round(Node * const node)3068 Node* SimplifiedLowering::Float64Round(Node* const node) {
3069 Node* const one = jsgraph()->Float64Constant(1.0);
3070 Node* const one_half = jsgraph()->Float64Constant(0.5);
3071 Node* const input = node->InputAt(0);
3072
3073 // Round up towards Infinity, and adjust if the difference exceeds 0.5.
3074 Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
3075 node->InputAt(0));
3076 return graph()->NewNode(
3077 common()->Select(MachineRepresentation::kFloat64),
3078 graph()->NewNode(
3079 machine()->Float64LessThanOrEqual(),
3080 graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
3081 result, graph()->NewNode(machine()->Float64Sub(), result, one));
3082 }
3083
Float64Sign(Node * const node)3084 Node* SimplifiedLowering::Float64Sign(Node* const node) {
3085 Node* const minus_one = jsgraph()->Float64Constant(-1.0);
3086 Node* const zero = jsgraph()->Float64Constant(0.0);
3087 Node* const one = jsgraph()->Float64Constant(1.0);
3088
3089 Node* const input = node->InputAt(0);
3090
3091 return graph()->NewNode(
3092 common()->Select(MachineRepresentation::kFloat64),
3093 graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
3094 graph()->NewNode(
3095 common()->Select(MachineRepresentation::kFloat64),
3096 graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
3097 input));
3098 }
3099
Int32Abs(Node * const node)3100 Node* SimplifiedLowering::Int32Abs(Node* const node) {
3101 Node* const input = node->InputAt(0);
3102
3103 // Generate case for absolute integer value.
3104 //
3105 // let sign = input >> 31 in
3106 // (input ^ sign) - sign
3107
3108 Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
3109 jsgraph()->Int32Constant(31));
3110 return graph()->NewNode(machine()->Int32Sub(),
3111 graph()->NewNode(machine()->Word32Xor(), input, sign),
3112 sign);
3113 }
3114
Int32Div(Node * const node)3115 Node* SimplifiedLowering::Int32Div(Node* const node) {
3116 Int32BinopMatcher m(node);
3117 Node* const zero = jsgraph()->Int32Constant(0);
3118 Node* const minus_one = jsgraph()->Int32Constant(-1);
3119 Node* const lhs = m.left().node();
3120 Node* const rhs = m.right().node();
3121
3122 if (m.right().Is(-1)) {
3123 return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3124 } else if (m.right().Is(0)) {
3125 return rhs;
3126 } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
3127 return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
3128 }
3129
3130 // General case for signed integer division.
3131 //
3132 // if 0 < rhs then
3133 // lhs / rhs
3134 // else
3135 // if rhs < -1 then
3136 // lhs / rhs
3137 // else if rhs == 0 then
3138 // 0
3139 // else
3140 // 0 - lhs
3141 //
3142 // Note: We do not use the Diamond helper class here, because it really hurts
3143 // readability with nested diamonds.
3144 const Operator* const merge_op = common()->Merge(2);
3145 const Operator* const phi_op =
3146 common()->Phi(MachineRepresentation::kWord32, 2);
3147
3148 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3149 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3150 graph()->start());
3151
3152 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3153 Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
3154
3155 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3156 Node* false0;
3157 {
3158 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3159 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3160
3161 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3162 Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
3163
3164 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3165 Node* false1;
3166 {
3167 Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3168 Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
3169
3170 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3171 Node* true2 = zero;
3172
3173 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3174 Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3175
3176 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3177 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3178 }
3179
3180 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3181 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3182 }
3183
3184 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3185 return graph()->NewNode(phi_op, true0, false0, merge0);
3186 }
3187
3188
Int32Mod(Node * const node)3189 Node* SimplifiedLowering::Int32Mod(Node* const node) {
3190 Int32BinopMatcher m(node);
3191 Node* const zero = jsgraph()->Int32Constant(0);
3192 Node* const minus_one = jsgraph()->Int32Constant(-1);
3193 Node* const lhs = m.left().node();
3194 Node* const rhs = m.right().node();
3195
3196 if (m.right().Is(-1) || m.right().Is(0)) {
3197 return zero;
3198 } else if (m.right().HasValue()) {
3199 return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
3200 }
3201
3202 // General case for signed integer modulus, with optimization for (unknown)
3203 // power of 2 right hand side.
3204 //
3205 // if 0 < rhs then
3206 // msk = rhs - 1
3207 // if rhs & msk != 0 then
3208 // lhs % rhs
3209 // else
3210 // if lhs < 0 then
3211 // -(-lhs & msk)
3212 // else
3213 // lhs & msk
3214 // else
3215 // if rhs < -1 then
3216 // lhs % rhs
3217 // else
3218 // zero
3219 //
3220 // Note: We do not use the Diamond helper class here, because it really hurts
3221 // readability with nested diamonds.
3222 const Operator* const merge_op = common()->Merge(2);
3223 const Operator* const phi_op =
3224 common()->Phi(MachineRepresentation::kWord32, 2);
3225
3226 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3227 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3228 graph()->start());
3229
3230 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3231 Node* true0;
3232 {
3233 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3234
3235 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3236 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
3237
3238 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3239 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3240
3241 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3242 Node* false1;
3243 {
3244 Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
3245 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
3246 check2, if_false1);
3247
3248 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3249 Node* true2 = graph()->NewNode(
3250 machine()->Int32Sub(), zero,
3251 graph()->NewNode(machine()->Word32And(),
3252 graph()->NewNode(machine()->Int32Sub(), zero, lhs),
3253 msk));
3254
3255 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3256 Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
3257
3258 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3259 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3260 }
3261
3262 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
3263 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
3264 }
3265
3266 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3267 Node* false0;
3268 {
3269 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3270 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
3271 check1, if_false0);
3272
3273 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3274 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3275
3276 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3277 Node* false1 = zero;
3278
3279 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3280 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3281 }
3282
3283 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3284 return graph()->NewNode(phi_op, true0, false0, merge0);
3285 }
3286
Int32Sign(Node * const node)3287 Node* SimplifiedLowering::Int32Sign(Node* const node) {
3288 Node* const minus_one = jsgraph()->Int32Constant(-1);
3289 Node* const zero = jsgraph()->Int32Constant(0);
3290 Node* const one = jsgraph()->Int32Constant(1);
3291
3292 Node* const input = node->InputAt(0);
3293
3294 return graph()->NewNode(
3295 common()->Select(MachineRepresentation::kWord32),
3296 graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
3297 graph()->NewNode(
3298 common()->Select(MachineRepresentation::kWord32),
3299 graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
3300 zero));
3301 }
3302
Uint32Div(Node * const node)3303 Node* SimplifiedLowering::Uint32Div(Node* const node) {
3304 Uint32BinopMatcher m(node);
3305 Node* const zero = jsgraph()->Uint32Constant(0);
3306 Node* const lhs = m.left().node();
3307 Node* const rhs = m.right().node();
3308
3309 if (m.right().Is(0)) {
3310 return zero;
3311 } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
3312 return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
3313 }
3314
3315 Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3316 Diamond d(graph(), common(), check, BranchHint::kFalse);
3317 Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
3318 return d.Phi(MachineRepresentation::kWord32, zero, div);
3319 }
3320
3321
Uint32Mod(Node * const node)3322 Node* SimplifiedLowering::Uint32Mod(Node* const node) {
3323 Uint32BinopMatcher m(node);
3324 Node* const minus_one = jsgraph()->Int32Constant(-1);
3325 Node* const zero = jsgraph()->Uint32Constant(0);
3326 Node* const lhs = m.left().node();
3327 Node* const rhs = m.right().node();
3328
3329 if (m.right().Is(0)) {
3330 return zero;
3331 } else if (m.right().HasValue()) {
3332 return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
3333 }
3334
3335 // General case for unsigned integer modulus, with optimization for (unknown)
3336 // power of 2 right hand side.
3337 //
3338 // if rhs then
3339 // msk = rhs - 1
3340 // if rhs & msk != 0 then
3341 // lhs % rhs
3342 // else
3343 // lhs & msk
3344 // else
3345 // zero
3346 //
3347 // Note: We do not use the Diamond helper class here, because it really hurts
3348 // readability with nested diamonds.
3349 const Operator* const merge_op = common()->Merge(2);
3350 const Operator* const phi_op =
3351 common()->Phi(MachineRepresentation::kWord32, 2);
3352
3353 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
3354 graph()->start());
3355
3356 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3357 Node* true0;
3358 {
3359 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3360
3361 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3362 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
3363
3364 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3365 Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
3366
3367 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3368 Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
3369
3370 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
3371 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
3372 }
3373
3374 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3375 Node* false0 = zero;
3376
3377 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3378 return graph()->NewNode(phi_op, true0, false0, merge0);
3379 }
3380
DoMax(Node * node,Operator const * op,MachineRepresentation rep)3381 void SimplifiedLowering::DoMax(Node* node, Operator const* op,
3382 MachineRepresentation rep) {
3383 Node* const lhs = node->InputAt(0);
3384 Node* const rhs = node->InputAt(1);
3385
3386 node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
3387 DCHECK_EQ(rhs, node->InputAt(1));
3388 node->AppendInput(graph()->zone(), lhs);
3389 NodeProperties::ChangeOp(node, common()->Select(rep));
3390 }
3391
DoMin(Node * node,Operator const * op,MachineRepresentation rep)3392 void SimplifiedLowering::DoMin(Node* node, Operator const* op,
3393 MachineRepresentation rep) {
3394 Node* const lhs = node->InputAt(0);
3395 Node* const rhs = node->InputAt(1);
3396
3397 node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
3398 DCHECK_EQ(lhs, node->InputAt(1));
3399 DCHECK_EQ(rhs, node->InputAt(2));
3400 NodeProperties::ChangeOp(node, common()->Select(rep));
3401 }
3402
DoShift(Node * node,Operator const * op,Type * rhs_type)3403 void SimplifiedLowering::DoShift(Node* node, Operator const* op,
3404 Type* rhs_type) {
3405 if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) {
3406 Node* const rhs = NodeProperties::GetValueInput(node, 1);
3407 node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
3408 jsgraph()->Int32Constant(0x1f)));
3409 }
3410 ChangeToPureOp(node, op);
3411 }
3412
DoStringToNumber(Node * node)3413 void SimplifiedLowering::DoStringToNumber(Node* node) {
3414 Operator::Properties properties = Operator::kEliminatable;
3415 Callable callable = CodeFactory::StringToNumber(isolate());
3416 CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
3417 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
3418 isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
3419 node->InsertInput(graph()->zone(), 0,
3420 jsgraph()->HeapConstant(callable.code()));
3421 node->AppendInput(graph()->zone(), jsgraph()->NoContextConstant());
3422 node->AppendInput(graph()->zone(), graph()->start());
3423 NodeProperties::ChangeOp(node, common()->Call(desc));
3424 }
3425
DoIntegral32ToBit(Node * node)3426 void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
3427 Node* const input = node->InputAt(0);
3428 Node* const zero = jsgraph()->Int32Constant(0);
3429 Operator const* const op = machine()->Word32Equal();
3430
3431 node->ReplaceInput(0, graph()->NewNode(op, input, zero));
3432 node->AppendInput(graph()->zone(), zero);
3433 NodeProperties::ChangeOp(node, op);
3434 }
3435
DoOrderedNumberToBit(Node * node)3436 void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
3437 Node* const input = node->InputAt(0);
3438
3439 node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
3440 jsgraph()->Float64Constant(0.0)));
3441 node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
3442 NodeProperties::ChangeOp(node, machine()->Word32Equal());
3443 }
3444
DoNumberToBit(Node * node)3445 void SimplifiedLowering::DoNumberToBit(Node* node) {
3446 Node* const input = node->InputAt(0);
3447
3448 node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
3449 node->AppendInput(graph()->zone(),
3450 graph()->NewNode(machine()->Float64Abs(), input));
3451 NodeProperties::ChangeOp(node, machine()->Float64LessThan());
3452 }
3453
DoIntegerToUint8Clamped(Node * node)3454 void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
3455 Node* const input = node->InputAt(0);
3456 Node* const min = jsgraph()->Float64Constant(0.0);
3457 Node* const max = jsgraph()->Float64Constant(255.0);
3458
3459 node->ReplaceInput(
3460 0, graph()->NewNode(machine()->Float64LessThan(), min, input));
3461 node->AppendInput(
3462 graph()->zone(),
3463 graph()->NewNode(
3464 common()->Select(MachineRepresentation::kFloat64),
3465 graph()->NewNode(machine()->Float64LessThan(), input, max), input,
3466 max));
3467 node->AppendInput(graph()->zone(), min);
3468 NodeProperties::ChangeOp(node,
3469 common()->Select(MachineRepresentation::kFloat64));
3470 }
3471
DoNumberToUint8Clamped(Node * node)3472 void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
3473 Node* const input = node->InputAt(0);
3474 Node* const min = jsgraph()->Float64Constant(0.0);
3475 Node* const max = jsgraph()->Float64Constant(255.0);
3476
3477 node->ReplaceInput(
3478 0, graph()->NewNode(
3479 common()->Select(MachineRepresentation::kFloat64),
3480 graph()->NewNode(machine()->Float64LessThan(), min, input),
3481 graph()->NewNode(
3482 common()->Select(MachineRepresentation::kFloat64),
3483 graph()->NewNode(machine()->Float64LessThan(), input, max),
3484 input, max),
3485 min));
3486 NodeProperties::ChangeOp(node,
3487 machine()->Float64RoundTiesEven().placeholder());
3488 }
3489
DoSigned32ToUint8Clamped(Node * node)3490 void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
3491 Node* const input = node->InputAt(0);
3492 Node* const min = jsgraph()->Int32Constant(0);
3493 Node* const max = jsgraph()->Int32Constant(255);
3494
3495 node->ReplaceInput(
3496 0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
3497 node->AppendInput(
3498 graph()->zone(),
3499 graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
3500 graph()->NewNode(machine()->Int32LessThan(), input, min),
3501 min, input));
3502 node->AppendInput(graph()->zone(), max);
3503 NodeProperties::ChangeOp(node,
3504 common()->Select(MachineRepresentation::kWord32));
3505 }
3506
DoUnsigned32ToUint8Clamped(Node * node)3507 void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
3508 Node* const input = node->InputAt(0);
3509 Node* const max = jsgraph()->Uint32Constant(255u);
3510
3511 node->ReplaceInput(
3512 0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
3513 node->AppendInput(graph()->zone(), input);
3514 node->AppendInput(graph()->zone(), max);
3515 NodeProperties::ChangeOp(node,
3516 common()->Select(MachineRepresentation::kWord32));
3517 }
3518
ToNumberCode()3519 Node* SimplifiedLowering::ToNumberCode() {
3520 if (!to_number_code_.is_set()) {
3521 Callable callable = CodeFactory::ToNumber(isolate());
3522 to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
3523 }
3524 return to_number_code_.get();
3525 }
3526
ToNumberOperator()3527 Operator const* SimplifiedLowering::ToNumberOperator() {
3528 if (!to_number_operator_.is_set()) {
3529 Callable callable = CodeFactory::ToNumber(isolate());
3530 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
3531 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
3532 isolate(), graph()->zone(), callable.descriptor(), 0, flags,
3533 Operator::kNoProperties);
3534 to_number_operator_.set(common()->Call(desc));
3535 }
3536 return to_number_operator_.get();
3537 }
3538
3539 } // namespace compiler
3540 } // namespace internal
3541 } // namespace v8
3542