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