• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/v8-fast-api-calls.h"
10 #include "src/base/bits.h"
11 #include "src/base/small-vector.h"
12 #include "src/codegen/code-factory.h"
13 #include "src/codegen/machine-type.h"
14 #include "src/codegen/tick-counter.h"
15 #include "src/compiler/access-builder.h"
16 #include "src/compiler/common-operator.h"
17 #include "src/compiler/compiler-source-position-table.h"
18 #include "src/compiler/diamond.h"
19 #include "src/compiler/graph-visualizer.h"
20 #include "src/compiler/js-heap-broker.h"
21 #include "src/compiler/linkage.h"
22 #include "src/compiler/node-matchers.h"
23 #include "src/compiler/node-observer.h"
24 #include "src/compiler/node-origin-table.h"
25 #include "src/compiler/operation-typer.h"
26 #include "src/compiler/operator-properties.h"
27 #include "src/compiler/representation-change.h"
28 #include "src/compiler/simplified-lowering-verifier.h"
29 #include "src/compiler/simplified-operator.h"
30 #include "src/compiler/type-cache.h"
31 #include "src/numbers/conversions-inl.h"
32 #include "src/objects/objects.h"
33 #include "src/utils/address-map.h"
34 
35 #if V8_ENABLE_WEBASSEMBLY
36 #include "src/wasm/value-type.h"
37 #endif  // V8_ENABLE_WEBASSEMBLY
38 
39 namespace v8 {
40 namespace internal {
41 namespace compiler {
42 
43 // Macro for outputting trace information from representation inference.
44 #define TRACE(...)                                      \
45   do {                                                  \
46     if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
47   } while (false)
48 
49 const char* kSimplifiedLoweringReducerName = "SimplifiedLowering";
50 
51 // Representation selection and lowering of {Simplified} operators to machine
52 // operators are interwined. We use a fixpoint calculation to compute both the
53 // output representation and the best possible lowering for {Simplified} nodes.
54 // Representation change insertion ensures that all values are in the correct
55 // machine representation after this phase, as dictated by the machine
56 // operators themselves.
57 enum Phase {
58   // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
59   //     backwards from uses to definitions, around cycles in phis, according
60   //     to local rules for each operator.
61   //     During this phase, the usage information for a node determines the best
62   //     possible lowering for each operator so far, and that in turn determines
63   //     the output representation.
64   //     Therefore, to be correct, this phase must iterate to a fixpoint before
65   //     the next phase can begin.
66   PROPAGATE,
67 
68   // 2.) RETYPE: Propagate types from type feedback forwards.
69   RETYPE,
70 
71   // 3.) LOWER: perform lowering for all {Simplified} nodes by replacing some
72   //     operators for some nodes, expanding some nodes to multiple nodes, or
73   //     removing some (redundant) nodes.
74   //     During this phase, use the {RepresentationChanger} to insert
75   //     representation changes between uses that demand a particular
76   //     representation and nodes that produce a different representation.
77   LOWER
78 };
79 
80 namespace {
81 
MachineRepresentationFromArrayType(ExternalArrayType array_type)82 MachineRepresentation MachineRepresentationFromArrayType(
83     ExternalArrayType array_type) {
84   switch (array_type) {
85     case kExternalUint8Array:
86     case kExternalUint8ClampedArray:
87     case kExternalInt8Array:
88       return MachineRepresentation::kWord8;
89     case kExternalUint16Array:
90     case kExternalInt16Array:
91       return MachineRepresentation::kWord16;
92     case kExternalUint32Array:
93     case kExternalInt32Array:
94       return MachineRepresentation::kWord32;
95     case kExternalFloat32Array:
96       return MachineRepresentation::kFloat32;
97     case kExternalFloat64Array:
98       return MachineRepresentation::kFloat64;
99     case kExternalBigInt64Array:
100     case kExternalBigUint64Array:
101       UNIMPLEMENTED();
102   }
103   UNREACHABLE();
104 }
105 
CheckedUseInfoAsWord32FromHint(NumberOperationHint hint,IdentifyZeros identify_zeros=kDistinguishZeros,const FeedbackSource & feedback=FeedbackSource ())106 UseInfo CheckedUseInfoAsWord32FromHint(
107     NumberOperationHint hint, IdentifyZeros identify_zeros = kDistinguishZeros,
108     const FeedbackSource& feedback = FeedbackSource()) {
109   switch (hint) {
110     case NumberOperationHint::kSignedSmall:
111     case NumberOperationHint::kSignedSmallInputs:
112       return UseInfo::CheckedSignedSmallAsWord32(identify_zeros, feedback);
113     case NumberOperationHint::kNumber:
114       DCHECK_EQ(identify_zeros, kIdentifyZeros);
115       return UseInfo::CheckedNumberAsWord32(feedback);
116     case NumberOperationHint::kNumberOrBoolean:
117       // Not used currently.
118       UNREACHABLE();
119     case NumberOperationHint::kNumberOrOddball:
120       DCHECK_EQ(identify_zeros, kIdentifyZeros);
121       return UseInfo::CheckedNumberOrOddballAsWord32(feedback);
122   }
123   UNREACHABLE();
124 }
125 
CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint,const FeedbackSource & feedback,IdentifyZeros identify_zeros=kDistinguishZeros)126 UseInfo CheckedUseInfoAsFloat64FromHint(
127     NumberOperationHint hint, const FeedbackSource& feedback,
128     IdentifyZeros identify_zeros = kDistinguishZeros) {
129   switch (hint) {
130     case NumberOperationHint::kSignedSmall:
131     case NumberOperationHint::kSignedSmallInputs:
132       // Not used currently.
133       UNREACHABLE();
134     case NumberOperationHint::kNumber:
135       return UseInfo::CheckedNumberAsFloat64(identify_zeros, feedback);
136     case NumberOperationHint::kNumberOrBoolean:
137       return UseInfo::CheckedNumberOrBooleanAsFloat64(identify_zeros, feedback);
138     case NumberOperationHint::kNumberOrOddball:
139       return UseInfo::CheckedNumberOrOddballAsFloat64(identify_zeros, feedback);
140   }
141   UNREACHABLE();
142 }
143 
TruncatingUseInfoFromRepresentation(MachineRepresentation rep)144 UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
145   switch (rep) {
146     case MachineRepresentation::kTaggedSigned:
147       return UseInfo::TaggedSigned();
148     case MachineRepresentation::kTaggedPointer:
149     case MachineRepresentation::kTagged:
150     case MachineRepresentation::kMapWord:
151       return UseInfo::AnyTagged();
152     case MachineRepresentation::kFloat64:
153       return UseInfo::TruncatingFloat64();
154     case MachineRepresentation::kFloat32:
155       return UseInfo::Float32();
156     case MachineRepresentation::kWord8:
157     case MachineRepresentation::kWord16:
158     case MachineRepresentation::kWord32:
159       return UseInfo::TruncatingWord32();
160     case MachineRepresentation::kWord64:
161       return UseInfo::Word64();
162     case MachineRepresentation::kBit:
163       return UseInfo::Bool();
164     case MachineRepresentation::kCompressedPointer:
165     case MachineRepresentation::kCompressed:
166     case MachineRepresentation::kSandboxedPointer:
167     case MachineRepresentation::kSimd128:
168     case MachineRepresentation::kNone:
169       break;
170   }
171   UNREACHABLE();
172 }
173 
UseInfoForBasePointer(const FieldAccess & access)174 UseInfo UseInfoForBasePointer(const FieldAccess& access) {
175   return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
176 }
177 
UseInfoForBasePointer(const ElementAccess & access)178 UseInfo UseInfoForBasePointer(const ElementAccess& access) {
179   return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
180 }
181 
ReplaceEffectControlUses(Node * node,Node * effect,Node * control)182 void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
183   for (Edge edge : node->use_edges()) {
184     if (NodeProperties::IsControlEdge(edge)) {
185       edge.UpdateTo(control);
186     } else if (NodeProperties::IsEffectEdge(edge)) {
187       edge.UpdateTo(effect);
188     } else {
189       DCHECK(NodeProperties::IsValueEdge(edge) ||
190              NodeProperties::IsContextEdge(edge));
191     }
192   }
193 }
194 
CanOverflowSigned32(const Operator * op,Type left,Type right,TypeCache const * type_cache,Zone * type_zone)195 bool CanOverflowSigned32(const Operator* op, Type left, Type right,
196                          TypeCache const* type_cache, Zone* type_zone) {
197   // We assume the inputs are checked Signed32 (or known statically to be
198   // Signed32). Technically, the inputs could also be minus zero, which we treat
199   // as 0 for the purpose of this function.
200   if (left.Maybe(Type::MinusZero())) {
201     left = Type::Union(left, type_cache->kSingletonZero, type_zone);
202   }
203   if (right.Maybe(Type::MinusZero())) {
204     right = Type::Union(right, type_cache->kSingletonZero, type_zone);
205   }
206   left = Type::Intersect(left, Type::Signed32(), type_zone);
207   right = Type::Intersect(right, Type::Signed32(), type_zone);
208   if (left.IsNone() || right.IsNone()) return false;
209   switch (op->opcode()) {
210     case IrOpcode::kSpeculativeSafeIntegerAdd:
211       return (left.Max() + right.Max() > kMaxInt) ||
212              (left.Min() + right.Min() < kMinInt);
213 
214     case IrOpcode::kSpeculativeSafeIntegerSubtract:
215       return (left.Max() - right.Min() > kMaxInt) ||
216              (left.Min() - right.Max() < kMinInt);
217 
218     default:
219       UNREACHABLE();
220   }
221 }
222 
IsSomePositiveOrderedNumber(Type type)223 bool IsSomePositiveOrderedNumber(Type type) {
224   return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0);
225 }
226 
227 class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter {
228  public:
JSONGraphWriterWithVerifierTypes(std::ostream & os,const Graph * graph,const SourcePositionTable * positions,const NodeOriginTable * origins,SimplifiedLoweringVerifier * verifier)229   JSONGraphWriterWithVerifierTypes(std::ostream& os, const Graph* graph,
230                                    const SourcePositionTable* positions,
231                                    const NodeOriginTable* origins,
232                                    SimplifiedLoweringVerifier* verifier)
233       : JSONGraphWriter(os, graph, positions, origins), verifier_(verifier) {}
234 
235  protected:
GetType(Node * node)236   base::Optional<Type> GetType(Node* node) override {
237     return verifier_->GetType(node);
238   }
239 
240  private:
241   SimplifiedLoweringVerifier* verifier_;
242 };
243 
244 }  // namespace
245 
246 #ifdef DEBUG
247 // Helpers for monotonicity checking.
248 class InputUseInfos {
249  public:
InputUseInfos(Zone * zone)250   explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
251 
SetAndCheckInput(Node * node,int index,UseInfo use_info)252   void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
253     if (input_use_infos_.empty()) {
254       input_use_infos_.resize(node->InputCount(), UseInfo::None());
255     }
256     // Check that the new use informatin is a super-type of the old
257     // one.
258     DCHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
259     input_use_infos_[index] = use_info;
260   }
261 
262  private:
263   ZoneVector<UseInfo> input_use_infos_;
264 
IsUseLessGeneral(UseInfo use1,UseInfo use2)265   static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
266     return use1.truncation().IsLessGeneralThan(use2.truncation());
267   }
268 };
269 
270 #endif  // DEBUG
271 
272 class RepresentationSelector {
273   // The purpose of this nested class is to hide method
274   // v8::internal::compiler::NodeProperties::ChangeOp which should not be
275   // directly used by code in RepresentationSelector and SimplifiedLowering.
276   // RepresentationSelector code should call RepresentationSelector::ChangeOp in
277   // place of NodeProperties::ChangeOp, in order to notify the changes to a
278   // registered ObserveNodeManager and support the %ObserveNode intrinsic.
279   class NodeProperties : public compiler::NodeProperties {
ChangeOp(Node * node,const Operator * new_op)280     static void ChangeOp(Node* node, const Operator* new_op) { UNREACHABLE(); }
281   };
282 
283  public:
284   // Information for each node tracked during the fixpoint.
285   class NodeInfo final {
286    public:
287     // Adds new use to the node. Returns true if something has changed
288     // and the node has to be requeued.
AddUse(UseInfo info)289     bool AddUse(UseInfo info) {
290       Truncation old_truncation = truncation_;
291       truncation_ = Truncation::Generalize(truncation_, info.truncation());
292       return truncation_ != old_truncation;
293     }
294 
set_queued()295     void set_queued() { state_ = kQueued; }
set_visited()296     void set_visited() { state_ = kVisited; }
set_pushed()297     void set_pushed() { state_ = kPushed; }
reset_state()298     void reset_state() { state_ = kUnvisited; }
visited() const299     bool visited() const { return state_ == kVisited; }
queued() const300     bool queued() const { return state_ == kQueued; }
pushed() const301     bool pushed() const { return state_ == kPushed; }
unvisited() const302     bool unvisited() const { return state_ == kUnvisited; }
truncation() const303     Truncation truncation() const { return truncation_; }
set_output(MachineRepresentation output)304     void set_output(MachineRepresentation output) { representation_ = output; }
305 
representation() const306     MachineRepresentation representation() const { return representation_; }
307 
308     // Helpers for feedback typing.
set_feedback_type(Type type)309     void set_feedback_type(Type type) { feedback_type_ = type; }
feedback_type() const310     Type feedback_type() const { return feedback_type_; }
set_weakened()311     void set_weakened() { weakened_ = true; }
weakened() const312     bool weakened() const { return weakened_; }
set_restriction_type(Type type)313     void set_restriction_type(Type type) { restriction_type_ = type; }
restriction_type() const314     Type restriction_type() const { return restriction_type_; }
315 
316    private:
317     // Fields are ordered to avoid mixing byte and word size fields to minimize
318     // padding.
319     enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
320     State state_ = kUnvisited;
321     MachineRepresentation representation_ =
322         MachineRepresentation::kNone;             // Output representation.
323     Truncation truncation_ = Truncation::None();  // Information about uses.
324     bool weakened_ = false;
325 
326     Type restriction_type_ = Type::Any();
327     Type feedback_type_;
328   };
329 
RepresentationSelector(JSGraph * jsgraph,JSHeapBroker * broker,Zone * zone,RepresentationChanger * changer,SourcePositionTable * source_positions,NodeOriginTable * node_origins,TickCounter * tick_counter,Linkage * linkage,ObserveNodeManager * observe_node_manager,SimplifiedLoweringVerifier * verifier)330   RepresentationSelector(JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
331                          RepresentationChanger* changer,
332                          SourcePositionTable* source_positions,
333                          NodeOriginTable* node_origins,
334                          TickCounter* tick_counter, Linkage* linkage,
335                          ObserveNodeManager* observe_node_manager,
336                          SimplifiedLoweringVerifier* verifier)
337       : jsgraph_(jsgraph),
338         broker_(broker),
339         zone_(zone),
340         might_need_revisit_(zone),
341         count_(jsgraph->graph()->NodeCount()),
342         info_(count_, zone),
343 #ifdef DEBUG
344         node_input_use_infos_(count_, InputUseInfos(zone), zone),
345 #endif
346         replacements_(zone),
347         changer_(changer),
348         revisit_queue_(zone),
349         traversal_nodes_(zone),
350         source_positions_(source_positions),
351         node_origins_(node_origins),
352         type_cache_(TypeCache::Get()),
353         op_typer_(broker, graph_zone()),
354         tick_counter_(tick_counter),
355         linkage_(linkage),
356         observe_node_manager_(observe_node_manager),
357         verifier_(verifier) {
358   }
359 
verification_enabled() const360   bool verification_enabled() const { return verifier_ != nullptr; }
361 
ResetNodeInfoState()362   void ResetNodeInfoState() {
363     // Clean up for the next phase.
364     for (NodeInfo& info : info_) {
365       info.reset_state();
366     }
367   }
368 
TypeOf(Node * node)369   Type TypeOf(Node* node) {
370     Type type = GetInfo(node)->feedback_type();
371     return type.IsInvalid() ? NodeProperties::GetType(node) : type;
372   }
373 
FeedbackTypeOf(Node * node)374   Type FeedbackTypeOf(Node* node) {
375     Type type = GetInfo(node)->feedback_type();
376     return type.IsInvalid() ? Type::None() : type;
377   }
378 
TypePhi(Node * node)379   Type TypePhi(Node* node) {
380     int arity = node->op()->ValueInputCount();
381     Type type = FeedbackTypeOf(node->InputAt(0));
382     for (int i = 1; i < arity; ++i) {
383       type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
384     }
385     return type;
386   }
387 
TypeSelect(Node * node)388   Type TypeSelect(Node* node) {
389     return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
390                            FeedbackTypeOf(node->InputAt(2)));
391   }
392 
UpdateFeedbackType(Node * node)393   bool UpdateFeedbackType(Node* node) {
394     if (node->op()->ValueOutputCount() == 0) return false;
395 
396     // For any non-phi node just wait until we get all inputs typed. We only
397     // allow untyped inputs for phi nodes because phis are the only places
398     // where cycles need to be broken.
399     if (node->opcode() != IrOpcode::kPhi) {
400       for (int i = 0; i < node->op()->ValueInputCount(); i++) {
401         if (GetInfo(node->InputAt(i))->feedback_type().IsInvalid()) {
402           return false;
403         }
404       }
405     }
406 
407     NodeInfo* info = GetInfo(node);
408     Type type = info->feedback_type();
409     Type new_type = NodeProperties::GetType(node);
410 
411     // We preload these values here to avoid increasing the binary size too
412     // much, which happens if we inline the calls into the macros below.
413     Type input0_type;
414     if (node->InputCount() > 0) input0_type = FeedbackTypeOf(node->InputAt(0));
415     Type input1_type;
416     if (node->InputCount() > 1) input1_type = FeedbackTypeOf(node->InputAt(1));
417 
418     switch (node->opcode()) {
419 #define DECLARE_CASE(Name)                               \
420   case IrOpcode::k##Name: {                              \
421     new_type = op_typer_.Name(input0_type, input1_type); \
422     break;                                               \
423   }
424       SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
425       DECLARE_CASE(SameValue)
426 #undef DECLARE_CASE
427 
428 #define DECLARE_CASE(Name)                                               \
429   case IrOpcode::k##Name: {                                              \
430     new_type = Type::Intersect(op_typer_.Name(input0_type, input1_type), \
431                                info->restriction_type(), graph_zone());  \
432     break;                                                               \
433   }
434       SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
435       SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_CASE)
436 #undef DECLARE_CASE
437 
438 #define DECLARE_CASE(Name)                  \
439   case IrOpcode::k##Name: {                 \
440     new_type = op_typer_.Name(input0_type); \
441     break;                                  \
442   }
443       SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
444 #undef DECLARE_CASE
445 
446 #define DECLARE_CASE(Name)                                              \
447   case IrOpcode::k##Name: {                                             \
448     new_type = Type::Intersect(op_typer_.Name(input0_type),             \
449                                info->restriction_type(), graph_zone()); \
450     break;                                                              \
451   }
452       SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
453 #undef DECLARE_CASE
454 
455       case IrOpcode::kConvertReceiver:
456         new_type = op_typer_.ConvertReceiver(input0_type);
457         break;
458 
459       case IrOpcode::kPlainPrimitiveToNumber:
460         new_type = op_typer_.ToNumber(input0_type);
461         break;
462 
463       case IrOpcode::kCheckBounds:
464         new_type =
465             Type::Intersect(op_typer_.CheckBounds(input0_type, input1_type),
466                             info->restriction_type(), graph_zone());
467         break;
468 
469       case IrOpcode::kCheckFloat64Hole:
470         new_type = Type::Intersect(op_typer_.CheckFloat64Hole(input0_type),
471                                    info->restriction_type(), graph_zone());
472         break;
473 
474       case IrOpcode::kCheckNumber:
475         new_type = Type::Intersect(op_typer_.CheckNumber(input0_type),
476                                    info->restriction_type(), graph_zone());
477         break;
478 
479       case IrOpcode::kPhi: {
480         new_type = TypePhi(node);
481         if (!type.IsInvalid()) {
482           new_type = Weaken(node, type, new_type);
483         }
484         break;
485       }
486 
487       case IrOpcode::kConvertTaggedHoleToUndefined:
488         new_type = op_typer_.ConvertTaggedHoleToUndefined(
489             FeedbackTypeOf(node->InputAt(0)));
490         break;
491 
492       case IrOpcode::kTypeGuard: {
493         new_type = op_typer_.TypeTypeGuard(node->op(),
494                                            FeedbackTypeOf(node->InputAt(0)));
495         break;
496       }
497 
498       case IrOpcode::kSelect: {
499         new_type = TypeSelect(node);
500         break;
501       }
502 
503       default:
504         // Shortcut for operations that we do not handle.
505         if (type.IsInvalid()) {
506           GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
507           return true;
508         }
509         return false;
510     }
511     // We need to guarantee that the feedback type is a subtype of the upper
512     // bound. Naively that should hold, but weakening can actually produce
513     // a bigger type if we are unlucky with ordering of phi typing. To be
514     // really sure, just intersect the upper bound with the feedback type.
515     new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());
516 
517     if (!type.IsInvalid() && new_type.Is(type)) return false;
518     GetInfo(node)->set_feedback_type(new_type);
519     if (FLAG_trace_representation) {
520       PrintNodeFeedbackType(node);
521     }
522     return true;
523   }
524 
PrintNodeFeedbackType(Node * n)525   void PrintNodeFeedbackType(Node* n) {
526     StdoutStream os;
527     os << "#" << n->id() << ":" << *n->op() << "(";
528     int j = 0;
529     for (Node* const i : n->inputs()) {
530       if (j++ > 0) os << ", ";
531       os << "#" << i->id() << ":" << i->op()->mnemonic();
532     }
533     os << ")";
534     if (NodeProperties::IsTyped(n)) {
535       Type static_type = NodeProperties::GetType(n);
536       os << "  [Static type: " << static_type;
537       Type feedback_type = GetInfo(n)->feedback_type();
538       if (!feedback_type.IsInvalid() && feedback_type != static_type) {
539         os << ", Feedback type: " << feedback_type;
540       }
541       os << "]";
542     }
543     os << std::endl;
544   }
545 
Weaken(Node * node,Type previous_type,Type current_type)546   Type Weaken(Node* node, Type previous_type, Type current_type) {
547     // If the types have nothing to do with integers, return the types.
548     Type const integer = type_cache_->kInteger;
549     if (!previous_type.Maybe(integer)) {
550       return current_type;
551     }
552     DCHECK(current_type.Maybe(integer));
553 
554     Type current_integer = Type::Intersect(current_type, integer, graph_zone());
555     DCHECK(!current_integer.IsNone());
556     Type previous_integer =
557         Type::Intersect(previous_type, integer, graph_zone());
558     DCHECK(!previous_integer.IsNone());
559 
560     // Once we start weakening a node, we should always weaken.
561     if (!GetInfo(node)->weakened()) {
562       // Only weaken if there is range involved; we should converge quickly
563       // for all other types (the exception is a union of many constants,
564       // but we currently do not increase the number of constants in unions).
565       Type previous = previous_integer.GetRange();
566       Type current = current_integer.GetRange();
567       if (current.IsInvalid() || previous.IsInvalid()) {
568         return current_type;
569       }
570       // Range is involved => we are weakening.
571       GetInfo(node)->set_weakened();
572     }
573 
574     return Type::Union(current_type,
575                        op_typer_.WeakenRange(previous_integer, current_integer),
576                        graph_zone());
577   }
578 
579   // Generates a pre-order traversal of the nodes, starting with End.
GenerateTraversal()580   void GenerateTraversal() {
581     // Reset previous state.
582     ResetNodeInfoState();
583     traversal_nodes_.clear();
584     count_ = graph()->NodeCount();
585     info_.resize(count_);
586 
587     ZoneStack<NodeState> stack(zone_);
588 
589     stack.push({graph()->end(), 0});
590     GetInfo(graph()->end())->set_pushed();
591     while (!stack.empty()) {
592       NodeState& current = stack.top();
593       Node* node = current.node;
594 
595       // If there is an unvisited input, push it and continue with that node.
596       bool pushed_unvisited = false;
597       while (current.input_index < node->InputCount()) {
598         Node* input = node->InputAt(current.input_index);
599         NodeInfo* input_info = GetInfo(input);
600         current.input_index++;
601         if (input_info->unvisited()) {
602           input_info->set_pushed();
603           stack.push({input, 0});
604           pushed_unvisited = true;
605           break;
606         } else if (input_info->pushed()) {
607           // Optimization for the Retype phase.
608           // If we had already pushed (and not visited) an input, it means that
609           // the current node will be visited in the Retype phase before one of
610           // its inputs. If this happens, the current node might need to be
611           // revisited.
612           MarkAsPossibleRevisit(node, input);
613         }
614       }
615 
616       if (pushed_unvisited) continue;
617 
618       stack.pop();
619       NodeInfo* info = GetInfo(node);
620       info->set_visited();
621 
622       // Generate the traversal
623       traversal_nodes_.push_back(node);
624     }
625   }
626 
PushNodeToRevisitIfVisited(Node * node)627   void PushNodeToRevisitIfVisited(Node* node) {
628     NodeInfo* info = GetInfo(node);
629     if (info->visited()) {
630       TRACE(" QUEUEING #%d: %s\n", node->id(), node->op()->mnemonic());
631       info->set_queued();
632       revisit_queue_.push(node);
633     }
634   }
635 
636   // Tries to update the feedback type of the node, as well as setting its
637   // machine representation (in VisitNode). Returns true iff updating the
638   // feedback type is successful.
RetypeNode(Node * node)639   bool RetypeNode(Node* node) {
640     NodeInfo* info = GetInfo(node);
641     info->set_visited();
642     bool updated = UpdateFeedbackType(node);
643     TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
644     VisitNode<RETYPE>(node, info->truncation(), nullptr);
645     TRACE("  ==> output %s\n", MachineReprToString(info->representation()));
646     return updated;
647   }
648 
649   // Visits the node and marks it as visited. Inside of VisitNode, we might
650   // change the truncation of one of our inputs (see EnqueueInput<PROPAGATE> for
651   // this). If we change the truncation of an already visited node, we will add
652   // it to the revisit queue.
PropagateTruncation(Node * node)653   void PropagateTruncation(Node* node) {
654     NodeInfo* info = GetInfo(node);
655     info->set_visited();
656     TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
657           info->truncation().description());
658     VisitNode<PROPAGATE>(node, info->truncation(), nullptr);
659   }
660 
661   // Backward propagation of truncations to a fixpoint.
RunPropagatePhase()662   void RunPropagatePhase() {
663     TRACE("--{Propagate phase}--\n");
664     ResetNodeInfoState();
665     DCHECK(revisit_queue_.empty());
666 
667     // Process nodes in reverse post order, with End as the root.
668     for (auto it = traversal_nodes_.crbegin(); it != traversal_nodes_.crend();
669          ++it) {
670       PropagateTruncation(*it);
671 
672       while (!revisit_queue_.empty()) {
673         Node* node = revisit_queue_.front();
674         revisit_queue_.pop();
675         PropagateTruncation(node);
676       }
677     }
678   }
679 
680   // Forward propagation of types from type feedback to a fixpoint.
RunRetypePhase()681   void RunRetypePhase() {
682     TRACE("--{Retype phase}--\n");
683     ResetNodeInfoState();
684     DCHECK(revisit_queue_.empty());
685 
686     for (auto it = traversal_nodes_.cbegin(); it != traversal_nodes_.cend();
687          ++it) {
688       Node* node = *it;
689       if (!RetypeNode(node)) continue;
690 
691       auto revisit_it = might_need_revisit_.find(node);
692       if (revisit_it == might_need_revisit_.end()) continue;
693 
694       for (Node* const user : revisit_it->second) {
695         PushNodeToRevisitIfVisited(user);
696       }
697 
698       // Process the revisit queue.
699       while (!revisit_queue_.empty()) {
700         Node* revisit_node = revisit_queue_.front();
701         revisit_queue_.pop();
702         if (!RetypeNode(revisit_node)) continue;
703         // Here we need to check all uses since we can't easily know which
704         // nodes will need to be revisited due to having an input which was
705         // a revisited node.
706         for (Node* const user : revisit_node->uses()) {
707           PushNodeToRevisitIfVisited(user);
708         }
709       }
710     }
711   }
712 
713   // Lowering and change insertion phase.
RunLowerPhase(SimplifiedLowering * lowering)714   void RunLowerPhase(SimplifiedLowering* lowering) {
715     TRACE("--{Lower phase}--\n");
716     for (auto it = traversal_nodes_.cbegin(); it != traversal_nodes_.cend();
717          ++it) {
718       Node* node = *it;
719       NodeInfo* info = GetInfo(node);
720       TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
721       // Reuse {VisitNode()} so the representation rules are in one place.
722       SourcePositionTable::Scope scope(
723           source_positions_, source_positions_->GetSourcePosition(node));
724       NodeOriginTable::Scope origin_scope(node_origins_, "simplified lowering",
725                                           node);
726       VisitNode<LOWER>(node, info->truncation(), lowering);
727     }
728 
729     // Perform the final replacements.
730     for (NodeVector::iterator i = replacements_.begin();
731          i != replacements_.end(); ++i) {
732       Node* node = *i;
733       Node* replacement = *(++i);
734       node->ReplaceUses(replacement);
735       node->Kill();
736       // We also need to replace the node in the rest of the vector.
737       for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
738         ++j;
739         if (*j == node) *j = replacement;
740       }
741     }
742   }
743 
RunVerifyPhase(OptimizedCompilationInfo * info)744   void RunVerifyPhase(OptimizedCompilationInfo* info) {
745     DCHECK_NOT_NULL(verifier_);
746 
747     TRACE("--{Verify Phase}--\n");
748 
749     // Generate a new traversal containing all the new nodes created during
750     // lowering.
751     GenerateTraversal();
752 
753     // Set node types to the refined types computed during retyping.
754     for (Node* node : traversal_nodes_) {
755       NodeInfo* info = GetInfo(node);
756       if (!info->feedback_type().IsInvalid()) {
757         NodeProperties::SetType(node, info->feedback_type());
758       }
759     }
760 
761     // Verify all nodes.
762     for (Node* node : traversal_nodes_) verifier_->VisitNode(node, op_typer_);
763 
764     // Print graph.
765     if (info != nullptr && info->trace_turbo_json()) {
766       UnparkedScopeIfNeeded scope(broker_);
767       AllowHandleDereference allow_deref;
768 
769       TurboJsonFile json_of(info, std::ios_base::app);
770       JSONGraphWriterWithVerifierTypes writer(
771           json_of, graph(), source_positions_, node_origins_, verifier_);
772       writer.PrintPhase("V8.TFSimplifiedLoweringVerifier");
773     }
774 
775     // Eliminate all introduced hints.
776     for (Node* node : verifier_->inserted_hints()) {
777       Node* input = node->InputAt(0);
778       node->ReplaceUses(input);
779       node->Kill();
780     }
781   }
782 
Run(SimplifiedLowering * lowering)783   void Run(SimplifiedLowering* lowering) {
784     GenerateTraversal();
785     RunPropagatePhase();
786     RunRetypePhase();
787     RunLowerPhase(lowering);
788 
789     if (verification_enabled()) {
790       RunVerifyPhase(lowering->info_);
791     }
792   }
793 
794   // Just assert for Retype and Lower. Propagate specialized below.
795   template <Phase T>
EnqueueInput(Node * use_node,int index,UseInfo use_info=UseInfo::None ())796   void EnqueueInput(Node* use_node, int index,
797                     UseInfo use_info = UseInfo::None()) {
798     static_assert(retype<T>() || lower<T>(),
799                   "This version of EnqueueInput has to be called in "
800                   "the Retype or Lower phase.");
801   }
802 
803   template <Phase T>
propagate()804   static constexpr bool propagate() {
805     return T == PROPAGATE;
806   }
807 
808   template <Phase T>
retype()809   static constexpr bool retype() {
810     return T == RETYPE;
811   }
812 
813   template <Phase T>
lower()814   static constexpr bool lower() {
815     return T == LOWER;
816   }
817 
818   template <Phase T>
819   void SetOutput(Node* node, MachineRepresentation representation,
820                  Type restriction_type = Type::Any());
821 
GetUpperBound(Node * node)822   Type GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
823 
InputCannotBe(Node * node,Type type)824   bool InputCannotBe(Node* node, Type type) {
825     DCHECK_EQ(1, node->op()->ValueInputCount());
826     return !GetUpperBound(node->InputAt(0)).Maybe(type);
827   }
828 
InputIs(Node * node,Type type)829   bool InputIs(Node* node, Type type) {
830     DCHECK_EQ(1, node->op()->ValueInputCount());
831     return GetUpperBound(node->InputAt(0)).Is(type);
832   }
833 
BothInputsAreSigned32(Node * node)834   bool BothInputsAreSigned32(Node* node) {
835     return BothInputsAre(node, Type::Signed32());
836   }
837 
BothInputsAreUnsigned32(Node * node)838   bool BothInputsAreUnsigned32(Node* node) {
839     return BothInputsAre(node, Type::Unsigned32());
840   }
841 
BothInputsAre(Node * node,Type type)842   bool BothInputsAre(Node* node, Type type) {
843     DCHECK_EQ(2, node->op()->ValueInputCount());
844     return GetUpperBound(node->InputAt(0)).Is(type) &&
845            GetUpperBound(node->InputAt(1)).Is(type);
846   }
847 
IsNodeRepresentationTagged(Node * node)848   bool IsNodeRepresentationTagged(Node* node) {
849     MachineRepresentation representation = GetInfo(node)->representation();
850     return IsAnyTagged(representation);
851   }
852 
OneInputCannotBe(Node * node,Type type)853   bool OneInputCannotBe(Node* node, Type type) {
854     DCHECK_EQ(2, node->op()->ValueInputCount());
855     return !GetUpperBound(node->InputAt(0)).Maybe(type) ||
856            !GetUpperBound(node->InputAt(1)).Maybe(type);
857   }
858 
ChangeToDeadValue(Node * node,Node * effect,Node * control)859   void ChangeToDeadValue(Node* node, Node* effect, Node* control) {
860     DCHECK(TypeOf(node).IsNone());
861     // If the node is unreachable, insert an Unreachable node and mark the
862     // value dead.
863     // TODO(jarin,turbofan) Find a way to unify/merge this insertion with
864     // InsertUnreachableIfNecessary.
865     Node* unreachable = effect =
866         graph()->NewNode(common()->Unreachable(), effect, control);
867     const Operator* dead_value =
868         common()->DeadValue(GetInfo(node)->representation());
869     node->ReplaceInput(0, unreachable);
870     node->TrimInputCount(dead_value->ValueInputCount());
871     ReplaceEffectControlUses(node, effect, control);
872     ChangeOp(node, dead_value);
873   }
874 
875   // This function is a generalization of ChangeToPureOp. It can be used to
876   // replace a node that is part of the effect and control chain by a pure node.
ReplaceWithPureNode(Node * node,Node * pure_node)877   void ReplaceWithPureNode(Node* node, Node* pure_node) {
878     DCHECK(pure_node->op()->HasProperty(Operator::kPure));
879     if (node->op()->EffectInputCount() > 0) {
880       DCHECK_LT(0, node->op()->ControlInputCount());
881       Node* control = NodeProperties::GetControlInput(node);
882       Node* effect = NodeProperties::GetEffectInput(node);
883       if (TypeOf(node).IsNone()) {
884         ChangeToDeadValue(node, effect, control);
885         return;
886       }
887       // Rewire the effect and control chains.
888       ReplaceEffectControlUses(node, effect, control);
889     } else {
890       DCHECK_EQ(0, node->op()->ControlInputCount());
891     }
892     DeferReplacement(node, pure_node);
893   }
894 
ChangeToPureOp(Node * node,const Operator * new_op)895   void ChangeToPureOp(Node* node, const Operator* new_op) {
896     DCHECK(new_op->HasProperty(Operator::kPure));
897     DCHECK_EQ(new_op->ValueInputCount(), node->op()->ValueInputCount());
898     if (node->op()->EffectInputCount() > 0) {
899       DCHECK_LT(0, node->op()->ControlInputCount());
900       Node* control = NodeProperties::GetControlInput(node);
901       Node* effect = NodeProperties::GetEffectInput(node);
902       if (TypeOf(node).IsNone()) {
903         ChangeToDeadValue(node, effect, control);
904         return;
905       }
906       // Rewire the effect and control chains.
907       node->TrimInputCount(new_op->ValueInputCount());
908       ReplaceEffectControlUses(node, effect, control);
909     } else {
910       DCHECK_EQ(0, node->op()->ControlInputCount());
911     }
912     ChangeOp(node, new_op);
913   }
914 
ChangeUnaryToPureBinaryOp(Node * node,const Operator * new_op,int new_input_index,Node * new_input)915   void ChangeUnaryToPureBinaryOp(Node* node, const Operator* new_op,
916                                  int new_input_index, Node* new_input) {
917     DCHECK(new_op->HasProperty(Operator::kPure));
918     DCHECK_EQ(new_op->ValueInputCount(), 2);
919     DCHECK_EQ(node->op()->ValueInputCount(), 1);
920     DCHECK_LE(0, new_input_index);
921     DCHECK_LE(new_input_index, 1);
922     if (node->op()->EffectInputCount() > 0) {
923       DCHECK_LT(0, node->op()->ControlInputCount());
924       Node* control = NodeProperties::GetControlInput(node);
925       Node* effect = NodeProperties::GetEffectInput(node);
926       if (TypeOf(node).IsNone()) {
927         ChangeToDeadValue(node, effect, control);
928         return;
929       }
930       node->TrimInputCount(node->op()->ValueInputCount());
931       ReplaceEffectControlUses(node, effect, control);
932     } else {
933       DCHECK_EQ(0, node->op()->ControlInputCount());
934     }
935     if (new_input_index == 0) {
936       node->InsertInput(jsgraph_->zone(), 0, new_input);
937     } else {
938       DCHECK_EQ(new_input_index, 1);
939       DCHECK_EQ(node->InputCount(), 1);
940       node->AppendInput(jsgraph_->zone(), new_input);
941     }
942     ChangeOp(node, new_op);
943   }
944 
945   // Converts input {index} of {node} according to given UseInfo {use},
946   // assuming the type of the input is {input_type}. If {input_type} is null,
947   // it takes the input from the input node {TypeOf(node->InputAt(index))}.
ConvertInput(Node * node,int index,UseInfo use,Type input_type=Type::Invalid ())948   void ConvertInput(Node* node, int index, UseInfo use,
949                     Type input_type = Type::Invalid()) {
950     // In the change phase, insert a change before the use if necessary.
951     if (use.representation() == MachineRepresentation::kNone)
952       return;  // No input requirement on the use.
953     Node* input = node->InputAt(index);
954     DCHECK_NOT_NULL(input);
955     NodeInfo* input_info = GetInfo(input);
956     MachineRepresentation input_rep = input_info->representation();
957     if (input_rep != use.representation() ||
958         use.type_check() != TypeCheckKind::kNone) {
959       // Output representation doesn't match usage.
960       TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
961             index, input->id(), input->op()->mnemonic());
962       TRACE("from %s to %s:%s\n",
963             MachineReprToString(input_info->representation()),
964             MachineReprToString(use.representation()),
965             use.truncation().description());
966       if (input_type.IsInvalid()) {
967         input_type = TypeOf(input);
968       }
969       Node* n = changer_->GetRepresentationFor(input, input_rep, input_type,
970                                                node, use);
971       node->ReplaceInput(index, n);
972     }
973   }
974 
975   template <Phase T>
976   void ProcessInput(Node* node, int index, UseInfo use);
977 
978   // Just assert for Retype and Lower. Propagate specialized below.
979   template <Phase T>
ProcessRemainingInputs(Node * node,int index)980   void ProcessRemainingInputs(Node* node, int index) {
981     static_assert(retype<T>() || lower<T>(),
982                   "This version of ProcessRemainingInputs has to be called in "
983                   "the Retype or Lower phase.");
984     DCHECK_GE(index, NodeProperties::PastValueIndex(node));
985     DCHECK_GE(index, NodeProperties::PastContextIndex(node));
986   }
987 
988   // Marks node as a possible revisit since it is a use of input that will be
989   // visited before input is visited.
MarkAsPossibleRevisit(Node * node,Node * input)990   void MarkAsPossibleRevisit(Node* node, Node* input) {
991     auto it = might_need_revisit_.find(input);
992     if (it == might_need_revisit_.end()) {
993       it = might_need_revisit_.insert({input, ZoneVector<Node*>(zone())}).first;
994     }
995     it->second.push_back(node);
996     TRACE(" Marking #%d: %s as needing revisit due to #%d: %s\n", node->id(),
997           node->op()->mnemonic(), input->id(), input->op()->mnemonic());
998   }
999 
1000   // Just assert for Retype. Propagate and Lower specialized below.
1001   template <Phase T>
VisitInputs(Node * node)1002   void VisitInputs(Node* node) {
1003     static_assert(
1004         retype<T>(),
1005         "This version of VisitInputs has to be called in the Retype phase.");
1006   }
1007 
1008   template <Phase T>
VisitReturn(Node * node)1009   void VisitReturn(Node* node) {
1010     int first_effect_index = NodeProperties::FirstEffectIndex(node);
1011     // Visit integer slot count to pop
1012     ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());
1013 
1014     // Visit value, context and frame state inputs as tagged.
1015     for (int i = 1; i < first_effect_index; i++) {
1016       ProcessInput<T>(node, i, UseInfo::AnyTagged());
1017     }
1018     // Only enqueue other inputs (effects, control).
1019     for (int i = first_effect_index; i < node->InputCount(); i++) {
1020       EnqueueInput<T>(node, i);
1021     }
1022   }
1023 
1024   // Helper for an unused node.
1025   template <Phase T>
VisitUnused(Node * node)1026   void VisitUnused(Node* node) {
1027     int first_effect_index = NodeProperties::FirstEffectIndex(node);
1028     for (int i = 0; i < first_effect_index; i++) {
1029       ProcessInput<T>(node, i, UseInfo::None());
1030     }
1031     ProcessRemainingInputs<T>(node, first_effect_index);
1032 
1033     if (lower<T>()) {
1034       TRACE("disconnecting unused #%d:%s\n", node->id(),
1035             node->op()->mnemonic());
1036       DisconnectFromEffectAndControl(node);
1037       node->NullAllInputs();  // Node is now dead.
1038       DeferReplacement(node, graph()->NewNode(common()->Plug()));
1039     }
1040   }
1041 
1042   // Helper for no-op node.
1043   template <Phase T>
VisitNoop(Node * node,Truncation truncation)1044   void VisitNoop(Node* node, Truncation truncation) {
1045     if (truncation.IsUnused()) return VisitUnused<T>(node);
1046     MachineRepresentation representation =
1047         GetOutputInfoForPhi(node, TypeOf(node), truncation);
1048     VisitUnop<T>(node, UseInfo(representation, truncation), representation);
1049     if (lower<T>()) DeferReplacement(node, node->InputAt(0));
1050   }
1051 
1052   // Helper for binops of the R x L -> O variety.
1053   template <Phase T>
VisitBinop(Node * node,UseInfo left_use,UseInfo right_use,MachineRepresentation output,Type restriction_type=Type::Any ())1054   void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
1055                   MachineRepresentation output,
1056                   Type restriction_type = Type::Any()) {
1057     DCHECK_EQ(2, node->op()->ValueInputCount());
1058     ProcessInput<T>(node, 0, left_use);
1059     ProcessInput<T>(node, 1, right_use);
1060     for (int i = 2; i < node->InputCount(); i++) {
1061       EnqueueInput<T>(node, i);
1062     }
1063     SetOutput<T>(node, output, restriction_type);
1064   }
1065 
1066   // Helper for binops of the I x I -> O variety.
1067   template <Phase T>
VisitBinop(Node * node,UseInfo input_use,MachineRepresentation output,Type restriction_type=Type::Any ())1068   void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output,
1069                   Type restriction_type = Type::Any()) {
1070     VisitBinop<T>(node, input_use, input_use, output, restriction_type);
1071   }
1072 
1073   template <Phase T>
VisitSpeculativeInt32Binop(Node * node)1074   void VisitSpeculativeInt32Binop(Node* node) {
1075     DCHECK_EQ(2, node->op()->ValueInputCount());
1076     if (BothInputsAre(node, Type::NumberOrOddball())) {
1077       return VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1078                            MachineRepresentation::kWord32);
1079     }
1080     NumberOperationHint hint = NumberOperationHintOf(node->op());
1081     return VisitBinop<T>(node,
1082                          CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
1083                          MachineRepresentation::kWord32);
1084   }
1085 
1086   // Helper for unops of the I -> O variety.
1087   template <Phase T>
VisitUnop(Node * node,UseInfo input_use,MachineRepresentation output,Type restriction_type=Type::Any ())1088   void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output,
1089                  Type restriction_type = Type::Any()) {
1090     DCHECK_EQ(1, node->op()->ValueInputCount());
1091     ProcessInput<T>(node, 0, input_use);
1092     ProcessRemainingInputs<T>(node, 1);
1093     SetOutput<T>(node, output, restriction_type);
1094   }
1095 
1096   // Helper for leaf nodes.
1097   template <Phase T>
VisitLeaf(Node * node,MachineRepresentation output)1098   void VisitLeaf(Node* node, MachineRepresentation output) {
1099     DCHECK_EQ(0, node->InputCount());
1100     SetOutput<T>(node, output);
1101   }
1102 
1103   // Helpers for specific types of binops.
1104 
1105   template <Phase T>
VisitFloat64Binop(Node * node)1106   void VisitFloat64Binop(Node* node) {
1107     VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
1108                   MachineRepresentation::kFloat64);
1109   }
1110 
1111   template <Phase T>
VisitInt64Binop(Node * node)1112   void VisitInt64Binop(Node* node) {
1113     VisitBinop<T>(node, UseInfo::Word64(), MachineRepresentation::kWord64);
1114   }
1115 
1116   template <Phase T>
VisitWord32TruncatingBinop(Node * node)1117   void VisitWord32TruncatingBinop(Node* node) {
1118     VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1119                   MachineRepresentation::kWord32);
1120   }
1121 
1122   // Infer representation for phi-like nodes.
1123   // The {node} parameter is only used to decide on the int64 representation.
1124   // Once the type system supports an external pointer type, the {node}
1125   // parameter can be removed.
GetOutputInfoForPhi(Node * node,Type type,Truncation use)1126   MachineRepresentation GetOutputInfoForPhi(Node* node, Type type,
1127                                             Truncation use) {
1128     // Compute the representation.
1129     if (type.Is(Type::None())) {
1130       return MachineRepresentation::kNone;
1131     } else if (type.Is(Type::Signed32()) || type.Is(Type::Unsigned32())) {
1132       return MachineRepresentation::kWord32;
1133     } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
1134       return MachineRepresentation::kWord32;
1135     } else if (type.Is(Type::Boolean())) {
1136       return MachineRepresentation::kBit;
1137     } else if (type.Is(Type::NumberOrOddball()) &&
1138                use.TruncatesOddballAndBigIntToNumber()) {
1139       return MachineRepresentation::kFloat64;
1140     } else if (type.Is(Type::Union(Type::SignedSmall(), Type::NaN(), zone()))) {
1141       // TODO(turbofan): For Phis that return either NaN or some Smi, it's
1142       // beneficial to not go all the way to double, unless the uses are
1143       // double uses. For tagging that just means some potentially expensive
1144       // allocation code; we might want to do the same for -0 as well?
1145       return MachineRepresentation::kTagged;
1146     } else if (type.Is(Type::Number())) {
1147       return MachineRepresentation::kFloat64;
1148     } else if (type.Is(Type::BigInt()) && use.IsUsedAsWord64()) {
1149       return MachineRepresentation::kWord64;
1150     } else if (type.Is(Type::ExternalPointer()) ||
1151                type.Is(Type::SandboxedPointer())) {
1152       return MachineType::PointerRepresentation();
1153     }
1154     return MachineRepresentation::kTagged;
1155   }
1156 
1157   // Helper for handling selects.
1158   template <Phase T>
VisitSelect(Node * node,Truncation truncation,SimplifiedLowering * lowering)1159   void VisitSelect(Node* node, Truncation truncation,
1160                    SimplifiedLowering* lowering) {
1161     DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
1162     ProcessInput<T>(node, 0, UseInfo::Bool());
1163 
1164     MachineRepresentation output =
1165         GetOutputInfoForPhi(node, TypeOf(node), truncation);
1166     SetOutput<T>(node, output);
1167 
1168     if (lower<T>()) {
1169       // Update the select operator.
1170       SelectParameters p = SelectParametersOf(node->op());
1171       if (output != p.representation()) {
1172         ChangeOp(node, lowering->common()->Select(output, p.hint()));
1173       }
1174     }
1175     // Convert inputs to the output representation of this phi, pass the
1176     // truncation truncation along.
1177     UseInfo input_use(output, truncation);
1178     ProcessInput<T>(node, 1, input_use);
1179     ProcessInput<T>(node, 2, input_use);
1180   }
1181 
1182   // Helper for handling phis.
1183   template <Phase T>
VisitPhi(Node * node,Truncation truncation,SimplifiedLowering * lowering)1184   void VisitPhi(Node* node, Truncation truncation,
1185                 SimplifiedLowering* lowering) {
1186     MachineRepresentation output =
1187         GetOutputInfoForPhi(node, TypeOf(node), truncation);
1188     // Only set the output representation if not running with type
1189     // feedback. (Feedback typing will set the representation.)
1190     SetOutput<T>(node, output);
1191 
1192     int values = node->op()->ValueInputCount();
1193     if (lower<T>()) {
1194       // Update the phi operator.
1195       if (output != PhiRepresentationOf(node->op())) {
1196         ChangeOp(node, lowering->common()->Phi(output, values));
1197       }
1198     }
1199 
1200     // Convert inputs to the output representation of this phi, pass the
1201     // truncation along.
1202     UseInfo input_use(output, truncation);
1203     for (int i = 0; i < node->InputCount(); i++) {
1204       ProcessInput<T>(node, i, i < values ? input_use : UseInfo::None());
1205     }
1206   }
1207 
1208   template <Phase T>
VisitObjectIs(Node * node,Type type,SimplifiedLowering * lowering)1209   void VisitObjectIs(Node* node, Type type, SimplifiedLowering* lowering) {
1210     Type const input_type = TypeOf(node->InputAt(0));
1211     if (input_type.Is(type)) {
1212       VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
1213       if (lower<T>()) {
1214         DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
1215       }
1216     } else {
1217       VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
1218       if (lower<T>() && !input_type.Maybe(type)) {
1219         DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1220       }
1221     }
1222   }
1223 
1224   template <Phase T>
VisitCheck(Node * node,Type type,SimplifiedLowering * lowering)1225   void VisitCheck(Node* node, Type type, SimplifiedLowering* lowering) {
1226     if (InputIs(node, type)) {
1227       VisitUnop<T>(node, UseInfo::AnyTagged(),
1228                    MachineRepresentation::kTaggedPointer);
1229       if (lower<T>()) DeferReplacement(node, node->InputAt(0));
1230     } else {
1231       VisitUnop<T>(node,
1232                    UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
1233                    MachineRepresentation::kTaggedPointer);
1234     }
1235   }
1236 
1237   template <Phase T>
VisitCall(Node * node,SimplifiedLowering * lowering)1238   void VisitCall(Node* node, SimplifiedLowering* lowering) {
1239     auto call_descriptor = CallDescriptorOf(node->op());
1240     int params = static_cast<int>(call_descriptor->ParameterCount());
1241     int value_input_count = node->op()->ValueInputCount();
1242 
1243     DCHECK_GT(value_input_count, 0);
1244     DCHECK_GE(value_input_count, params);
1245 
1246     // The target of the call.
1247     ProcessInput<T>(node, 0, UseInfo::Any());
1248 
1249     // For the parameters (indexes [1, ..., params]), propagate representation
1250     // information from call descriptor.
1251     for (int i = 1; i <= params; i++) {
1252       ProcessInput<T>(node, i,
1253                       TruncatingUseInfoFromRepresentation(
1254                           call_descriptor->GetInputType(i).representation()));
1255     }
1256 
1257     // Rest of the value inputs.
1258     for (int i = params + 1; i < value_input_count; i++) {
1259       ProcessInput<T>(node, i, UseInfo::AnyTagged());
1260     }
1261 
1262     // Effect and Control.
1263     ProcessRemainingInputs<T>(node, value_input_count);
1264 
1265     if (call_descriptor->ReturnCount() > 0) {
1266       SetOutput<T>(node, call_descriptor->GetReturnType(0).representation());
1267     } else {
1268       SetOutput<T>(node, MachineRepresentation::kTagged);
1269     }
1270   }
1271 
MaskShiftOperand(Node * node,Type rhs_type)1272   void MaskShiftOperand(Node* node, Type rhs_type) {
1273     if (!rhs_type.Is(type_cache_->kZeroToThirtyOne)) {
1274       Node* const rhs = NodeProperties::GetValueInput(node, 1);
1275       node->ReplaceInput(1,
1276                          graph()->NewNode(jsgraph_->machine()->Word32And(), rhs,
1277                                           jsgraph_->Int32Constant(0x1F)));
1278     }
1279   }
1280 
DeoptValueSemanticOf(Type type)1281   static MachineSemantic DeoptValueSemanticOf(Type type) {
1282     // We only need signedness to do deopt correctly.
1283     if (type.Is(Type::Signed32())) {
1284       return MachineSemantic::kInt32;
1285     } else if (type.Is(Type::Unsigned32())) {
1286       return MachineSemantic::kUint32;
1287     } else {
1288       return MachineSemantic::kAny;
1289     }
1290   }
1291 
DeoptMachineTypeOf(MachineRepresentation rep,Type type)1292   static MachineType DeoptMachineTypeOf(MachineRepresentation rep, Type type) {
1293     if (type.IsNone()) {
1294       return MachineType::None();
1295     }
1296     // Do not distinguish between various Tagged variations.
1297     if (IsAnyTagged(rep)) {
1298       return MachineType::AnyTagged();
1299     }
1300     if (rep == MachineRepresentation::kWord64) {
1301       if (type.Is(Type::BigInt())) {
1302         return MachineType::AnyTagged();
1303       }
1304 
1305       DCHECK(type.Is(TypeCache::Get()->kSafeInteger));
1306       return MachineType(rep, MachineSemantic::kInt64);
1307     }
1308     MachineType machine_type(rep, DeoptValueSemanticOf(type));
1309     DCHECK(machine_type.representation() != MachineRepresentation::kWord32 ||
1310            machine_type.semantic() == MachineSemantic::kInt32 ||
1311            machine_type.semantic() == MachineSemantic::kUint32);
1312     DCHECK(machine_type.representation() != MachineRepresentation::kBit ||
1313            type.Is(Type::Boolean()));
1314     return machine_type;
1315   }
1316 
1317   template <Phase T>
VisitStateValues(Node * node)1318   void VisitStateValues(Node* node) {
1319     if (propagate<T>()) {
1320       for (int i = 0; i < node->InputCount(); i++) {
1321         // When lowering 64 bit BigInts to Word64 representation, we have to
1322         // make sure they are rematerialized before deoptimization. By
1323         // propagating a AnyTagged use, the RepresentationChanger is going to
1324         // insert the necessary conversions.
1325         // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1326         // truncated BigInts.
1327         if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1328           EnqueueInput<T>(node, i, UseInfo::AnyTagged());
1329         } else {
1330           EnqueueInput<T>(node, i, UseInfo::Any());
1331         }
1332       }
1333     } else if (lower<T>()) {
1334       Zone* zone = jsgraph_->zone();
1335       ZoneVector<MachineType>* types =
1336           zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
1337       for (int i = 0; i < node->InputCount(); i++) {
1338         Node* input = node->InputAt(i);
1339         // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1340         // truncated BigInts.
1341         if (TypeOf(input).Is(Type::BigInt())) {
1342           ConvertInput(node, i, UseInfo::AnyTagged());
1343         }
1344 
1345         (*types)[i] =
1346             DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1347       }
1348       SparseInputMask mask = SparseInputMaskOf(node->op());
1349       ChangeOp(node, common()->TypedStateValues(types, mask));
1350     }
1351     SetOutput<T>(node, MachineRepresentation::kTagged);
1352   }
1353 
1354   template <Phase T>
VisitFrameState(FrameState node)1355   void VisitFrameState(FrameState node) {
1356     DCHECK_EQ(5, node->op()->ValueInputCount());
1357     DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
1358     DCHECK_EQ(FrameState::kFrameStateInputCount, node->InputCount());
1359 
1360     ProcessInput<T>(node, FrameState::kFrameStateParametersInput,
1361                     UseInfo::AnyTagged());
1362     ProcessInput<T>(node, FrameState::kFrameStateLocalsInput,
1363                     UseInfo::AnyTagged());
1364 
1365     // Accumulator is a special flower - we need to remember its type in
1366     // a singleton typed-state-values node (as if it was a singleton
1367     // state-values node).
1368     Node* accumulator = node.stack();
1369     if (propagate<T>()) {
1370       // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1371       // truncated BigInts.
1372       if (TypeOf(accumulator).Is(Type::BigInt())) {
1373         EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
1374                         UseInfo::AnyTagged());
1375       } else {
1376         EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
1377                         UseInfo::Any());
1378       }
1379     } else if (lower<T>()) {
1380       // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1381       // truncated BigInts.
1382       if (TypeOf(accumulator).Is(Type::BigInt())) {
1383         ConvertInput(node, FrameState::kFrameStateStackInput,
1384                      UseInfo::AnyTagged());
1385       }
1386       Zone* zone = jsgraph_->zone();
1387       if (accumulator == jsgraph_->OptimizedOutConstant()) {
1388         node->ReplaceInput(FrameState::kFrameStateStackInput,
1389                            jsgraph_->SingleDeadTypedStateValues());
1390       } else {
1391         ZoneVector<MachineType>* types =
1392             zone->New<ZoneVector<MachineType>>(1, zone);
1393         (*types)[0] = DeoptMachineTypeOf(GetInfo(accumulator)->representation(),
1394                                          TypeOf(accumulator));
1395 
1396         node->ReplaceInput(
1397             FrameState::kFrameStateStackInput,
1398             jsgraph_->graph()->NewNode(
1399                 common()->TypedStateValues(types, SparseInputMask::Dense()),
1400                 node.stack()));
1401       }
1402     }
1403 
1404     ProcessInput<T>(node, FrameState::kFrameStateContextInput,
1405                     UseInfo::AnyTagged());
1406     ProcessInput<T>(node, FrameState::kFrameStateFunctionInput,
1407                     UseInfo::AnyTagged());
1408     ProcessInput<T>(node, FrameState::kFrameStateOuterStateInput,
1409                     UseInfo::AnyTagged());
1410     return SetOutput<T>(node, MachineRepresentation::kTagged);
1411   }
1412 
1413   template <Phase T>
VisitObjectState(Node * node)1414   void VisitObjectState(Node* node) {
1415     if (propagate<T>()) {
1416       for (int i = 0; i < node->InputCount(); i++) {
1417         // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1418         // truncated BigInts.
1419         if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1420           EnqueueInput<T>(node, i, UseInfo::AnyTagged());
1421         } else {
1422           EnqueueInput<T>(node, i, UseInfo::Any());
1423         }
1424       }
1425     } else if (lower<T>()) {
1426       Zone* zone = jsgraph_->zone();
1427       ZoneVector<MachineType>* types =
1428           zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
1429       for (int i = 0; i < node->InputCount(); i++) {
1430         Node* input = node->InputAt(i);
1431         (*types)[i] =
1432             DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1433         // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1434         // truncated BigInts.
1435         if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1436           ConvertInput(node, i, UseInfo::AnyTagged());
1437         }
1438       }
1439       ChangeOp(node, common()->TypedObjectState(ObjectIdOf(node->op()), types));
1440     }
1441     SetOutput<T>(node, MachineRepresentation::kTagged);
1442   }
1443 
Int32Op(Node * node)1444   const Operator* Int32Op(Node* node) {
1445     return changer_->Int32OperatorFor(node->opcode());
1446   }
1447 
Int32OverflowOp(Node * node)1448   const Operator* Int32OverflowOp(Node* node) {
1449     return changer_->Int32OverflowOperatorFor(node->opcode());
1450   }
1451 
Int64Op(Node * node)1452   const Operator* Int64Op(Node* node) {
1453     return changer_->Int64OperatorFor(node->opcode());
1454   }
1455 
Uint32Op(Node * node)1456   const Operator* Uint32Op(Node* node) {
1457     return changer_->Uint32OperatorFor(node->opcode());
1458   }
1459 
Uint32OverflowOp(Node * node)1460   const Operator* Uint32OverflowOp(Node* node) {
1461     return changer_->Uint32OverflowOperatorFor(node->opcode());
1462   }
1463 
Float64Op(Node * node)1464   const Operator* Float64Op(Node* node) {
1465     return changer_->Float64OperatorFor(node->opcode());
1466   }
1467 
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,Type field_type,MachineRepresentation value_representation,Node * value)1468   WriteBarrierKind WriteBarrierKindFor(
1469       BaseTaggedness base_taggedness,
1470       MachineRepresentation field_representation, Type field_type,
1471       MachineRepresentation value_representation, Node* value) {
1472     if (base_taggedness == kTaggedBase &&
1473         CanBeTaggedPointer(field_representation)) {
1474       Type value_type = NodeProperties::GetType(value);
1475       if (value_representation == MachineRepresentation::kTaggedSigned) {
1476         // Write barriers are only for stores of heap objects.
1477         return kNoWriteBarrier;
1478       }
1479       if (field_type.Is(Type::BooleanOrNullOrUndefined()) ||
1480           value_type.Is(Type::BooleanOrNullOrUndefined())) {
1481         // Write barriers are not necessary when storing true, false, null or
1482         // undefined, because these special oddballs are always in the root set.
1483         return kNoWriteBarrier;
1484       }
1485       if (value_type.IsHeapConstant()) {
1486         RootIndex root_index;
1487         const RootsTable& roots_table = jsgraph_->isolate()->roots_table();
1488         if (roots_table.IsRootHandle(value_type.AsHeapConstant()->Value(),
1489                                      &root_index)) {
1490           if (RootsTable::IsImmortalImmovable(root_index)) {
1491             // Write barriers are unnecessary for immortal immovable roots.
1492             return kNoWriteBarrier;
1493           }
1494         }
1495       }
1496       if (field_representation == MachineRepresentation::kTaggedPointer ||
1497           value_representation == MachineRepresentation::kTaggedPointer) {
1498         // Write barriers for heap objects are cheaper.
1499         return kPointerWriteBarrier;
1500       }
1501       NumberMatcher m(value);
1502       if (m.HasResolvedValue()) {
1503         if (IsSmiDouble(m.ResolvedValue())) {
1504           // Storing a smi doesn't need a write barrier.
1505           return kNoWriteBarrier;
1506         }
1507         // The NumberConstant will be represented as HeapNumber.
1508         return kPointerWriteBarrier;
1509       }
1510       return kFullWriteBarrier;
1511     }
1512     return kNoWriteBarrier;
1513   }
1514 
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,int field_offset,Type field_type,MachineRepresentation value_representation,Node * value)1515   WriteBarrierKind WriteBarrierKindFor(
1516       BaseTaggedness base_taggedness,
1517       MachineRepresentation field_representation, int field_offset,
1518       Type field_type, MachineRepresentation value_representation,
1519       Node* value) {
1520     WriteBarrierKind write_barrier_kind =
1521         WriteBarrierKindFor(base_taggedness, field_representation, field_type,
1522                             value_representation, value);
1523     if (write_barrier_kind != kNoWriteBarrier) {
1524       if (base_taggedness == kTaggedBase &&
1525           field_offset == HeapObject::kMapOffset) {
1526         write_barrier_kind = kMapWriteBarrier;
1527       }
1528     }
1529     return write_barrier_kind;
1530   }
1531 
graph() const1532   Graph* graph() const { return jsgraph_->graph(); }
common() const1533   CommonOperatorBuilder* common() const { return jsgraph_->common(); }
simplified() const1534   SimplifiedOperatorBuilder* simplified() const {
1535     return jsgraph_->simplified();
1536   }
1537 
1538   template <Phase T>
VisitForCheckedInt32Mul(Node * node,Truncation truncation,Type input0_type,Type input1_type,UseInfo input_use)1539   void VisitForCheckedInt32Mul(Node* node, Truncation truncation,
1540                                Type input0_type, Type input1_type,
1541                                UseInfo input_use) {
1542     DCHECK_EQ(node->opcode(), IrOpcode::kSpeculativeNumberMultiply);
1543     // A -0 input is impossible or will cause a deopt.
1544     DCHECK(BothInputsAre(node, Type::Signed32()) ||
1545            !input_use.truncation().IdentifiesZeroAndMinusZero());
1546 
1547     CheckForMinusZeroMode mz_mode;
1548     Type restriction;
1549     if (IsSomePositiveOrderedNumber(input0_type) ||
1550         IsSomePositiveOrderedNumber(input1_type)) {
1551       mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero;
1552       restriction = Type::Signed32();
1553     } else if (truncation.IdentifiesZeroAndMinusZero()) {
1554       mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero;
1555       restriction = Type::Signed32OrMinusZero();
1556     } else {
1557       mz_mode = CheckForMinusZeroMode::kCheckForMinusZero;
1558       restriction = Type::Signed32();
1559     }
1560 
1561     VisitBinop<T>(node, input_use, MachineRepresentation::kWord32, restriction);
1562     if (lower<T>()) ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
1563   }
1564 
ChangeToInt32OverflowOp(Node * node)1565   void ChangeToInt32OverflowOp(Node* node) {
1566     ChangeOp(node, Int32OverflowOp(node));
1567   }
1568 
ChangeToUint32OverflowOp(Node * node)1569   void ChangeToUint32OverflowOp(Node* node) {
1570     ChangeOp(node, Uint32OverflowOp(node));
1571   }
1572 
1573   template <Phase T>
VisitSpeculativeIntegerAdditiveOp(Node * node,Truncation truncation,SimplifiedLowering * lowering)1574   void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation,
1575                                          SimplifiedLowering* lowering) {
1576     Type left_upper = GetUpperBound(node->InputAt(0));
1577     Type right_upper = GetUpperBound(node->InputAt(1));
1578 
1579     if (left_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1580         right_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero)) {
1581       // Only eliminate the node if its typing rule can be satisfied, namely
1582       // that a safe integer is produced.
1583       if (truncation.IsUnused()) return VisitUnused<T>(node);
1584 
1585       // If we know how to interpret the result or if the users only care
1586       // about the low 32-bits, we can truncate to Word32 do a wrapping
1587       // addition.
1588       if (GetUpperBound(node).Is(Type::Signed32()) ||
1589           GetUpperBound(node).Is(Type::Unsigned32()) ||
1590           truncation.IsUsedAsWord32()) {
1591         // => Int32Add/Sub
1592         VisitWord32TruncatingBinop<T>(node);
1593         if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
1594         return;
1595       }
1596     }
1597 
1598     // Try to use type feedback.
1599     NumberOperationHint const hint = NumberOperationHint::kSignedSmall;
1600     DCHECK_EQ(hint, NumberOperationHintOf(node->op()));
1601 
1602     Type left_feedback_type = TypeOf(node->InputAt(0));
1603     Type right_feedback_type = TypeOf(node->InputAt(1));
1604 
1605     // Using Signed32 as restriction type amounts to promising there won't be
1606     // signed overflow. This is incompatible with relying on a Word32 truncation
1607     // in order to skip the overflow check.  Similarly, we must not drop -0 from
1608     // the result type unless we deopt for -0 inputs.
1609     Type const restriction =
1610         truncation.IsUsedAsWord32()
1611             ? Type::Any()
1612             : (truncation.identify_zeros() == kIdentifyZeros)
1613                   ? Type::Signed32OrMinusZero()
1614                   : Type::Signed32();
1615 
1616     // Handle the case when no int32 checks on inputs are necessary (but
1617     // an overflow check is needed on the output). Note that we do not
1618     // have to do any check if at most one side can be minus zero. For
1619     // subtraction we need to handle the case of -0 - 0 properly, since
1620     // that can produce -0.
1621     Type left_constraint_type =
1622         node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd
1623             ? Type::Signed32OrMinusZero()
1624             : Type::Signed32();
1625     if (left_upper.Is(left_constraint_type) &&
1626         right_upper.Is(Type::Signed32OrMinusZero()) &&
1627         (left_upper.Is(Type::Signed32()) || right_upper.Is(Type::Signed32()))) {
1628       VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1629                     MachineRepresentation::kWord32, restriction);
1630     } else {
1631       // If the output's truncation is identify-zeros, we can pass it
1632       // along. Moreover, if the operation is addition and we know the
1633       // right-hand side is not minus zero, we do not have to distinguish
1634       // between 0 and -0.
1635       IdentifyZeros left_identify_zeros = truncation.identify_zeros();
1636       if (node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd &&
1637           !right_feedback_type.Maybe(Type::MinusZero())) {
1638         left_identify_zeros = kIdentifyZeros;
1639       }
1640       UseInfo left_use =
1641           CheckedUseInfoAsWord32FromHint(hint, left_identify_zeros);
1642       // For CheckedInt32Add and CheckedInt32Sub, we don't need to do
1643       // a minus zero check for the right hand side, since we already
1644       // know that the left hand side is a proper Signed32 value,
1645       // potentially guarded by a check.
1646       UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros);
1647       VisitBinop<T>(node, left_use, right_use, MachineRepresentation::kWord32,
1648                     restriction);
1649     }
1650 
1651     if (lower<T>()) {
1652       if (truncation.IsUsedAsWord32() ||
1653           !CanOverflowSigned32(node->op(), left_feedback_type,
1654                                right_feedback_type, type_cache_,
1655                                graph_zone())) {
1656         ChangeToPureOp(node, Int32Op(node));
1657       } else {
1658         ChangeToInt32OverflowOp(node);
1659       }
1660     }
1661     return;
1662   }
1663 
1664   template <Phase T>
VisitSpeculativeAdditiveOp(Node * node,Truncation truncation,SimplifiedLowering * lowering)1665   void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
1666                                   SimplifiedLowering* lowering) {
1667     if (BothInputsAre(node, type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1668         (GetUpperBound(node).Is(Type::Signed32()) ||
1669          GetUpperBound(node).Is(Type::Unsigned32()) ||
1670          truncation.IsUsedAsWord32())) {
1671       // => Int32Add/Sub
1672       VisitWord32TruncatingBinop<T>(node);
1673       if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
1674       return;
1675     }
1676 
1677     // default case => Float64Add/Sub
1678     VisitBinop<T>(node,
1679                   UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1680                                                            FeedbackSource()),
1681                   MachineRepresentation::kFloat64, Type::Number());
1682     if (lower<T>()) {
1683       ChangeToPureOp(node, Float64Op(node));
1684     }
1685     return;
1686   }
1687 
1688   template <Phase T>
VisitSpeculativeNumberModulus(Node * node,Truncation truncation,SimplifiedLowering * lowering)1689   void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
1690                                      SimplifiedLowering* lowering) {
1691     if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1692         (truncation.IsUsedAsWord32() ||
1693          NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1694       // => unsigned Uint32Mod
1695       VisitWord32TruncatingBinop<T>(node);
1696       if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
1697       return;
1698     }
1699     if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1700         (truncation.IsUsedAsWord32() ||
1701          NodeProperties::GetType(node).Is(Type::Signed32()))) {
1702       // => signed Int32Mod
1703       VisitWord32TruncatingBinop<T>(node);
1704       if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1705       return;
1706     }
1707 
1708     // Try to use type feedback.
1709     NumberOperationHint hint = NumberOperationHintOf(node->op());
1710 
1711     // Handle the case when no uint32 checks on inputs are necessary
1712     // (but an overflow check is needed on the output).
1713     if (BothInputsAreUnsigned32(node)) {
1714       if (hint == NumberOperationHint::kSignedSmall) {
1715         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1716                       MachineRepresentation::kWord32, Type::Unsigned32());
1717         if (lower<T>()) ChangeToUint32OverflowOp(node);
1718         return;
1719       }
1720     }
1721 
1722     // Handle the case when no int32 checks on inputs are necessary
1723     // (but an overflow check is needed on the output).
1724     if (BothInputsAre(node, Type::Signed32())) {
1725       // If both the inputs the feedback are int32, use the overflow op.
1726       if (hint == NumberOperationHint::kSignedSmall) {
1727         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1728                       MachineRepresentation::kWord32, Type::Signed32());
1729         if (lower<T>()) ChangeToInt32OverflowOp(node);
1730         return;
1731       }
1732     }
1733 
1734     if (hint == NumberOperationHint::kSignedSmall) {
1735       // If the result is truncated, we only need to check the inputs.
1736       // For the left hand side we just propagate the identify zeros
1737       // mode of the {truncation}; and for modulus the sign of the
1738       // right hand side doesn't matter anyways, so in particular there's
1739       // no observable difference between a 0 and a -0 then.
1740       UseInfo const lhs_use =
1741           CheckedUseInfoAsWord32FromHint(hint, truncation.identify_zeros());
1742       UseInfo const rhs_use =
1743           CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros);
1744       if (truncation.IsUsedAsWord32()) {
1745         VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
1746         if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1747       } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
1748         Type const restriction =
1749             truncation.IdentifiesZeroAndMinusZero() &&
1750                     TypeOf(node->InputAt(0)).Maybe(Type::MinusZero())
1751                 ? Type::Unsigned32OrMinusZero()
1752                 : Type::Unsigned32();
1753         VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
1754                       restriction);
1755         if (lower<T>()) ChangeToUint32OverflowOp(node);
1756       } else {
1757         Type const restriction =
1758             truncation.IdentifiesZeroAndMinusZero() &&
1759                     TypeOf(node->InputAt(0)).Maybe(Type::MinusZero())
1760                 ? Type::Signed32OrMinusZero()
1761                 : Type::Signed32();
1762         VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
1763                       restriction);
1764         if (lower<T>()) ChangeToInt32OverflowOp(node);
1765       }
1766       return;
1767     }
1768 
1769     if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
1770         TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
1771         (truncation.IsUsedAsWord32() ||
1772          NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1773       VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1774                     MachineRepresentation::kWord32, Type::Number());
1775       if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
1776       return;
1777     }
1778     if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
1779         TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
1780         (truncation.IsUsedAsWord32() ||
1781          NodeProperties::GetType(node).Is(Type::Signed32()))) {
1782       VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1783                     MachineRepresentation::kWord32, Type::Number());
1784       if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1785       return;
1786     }
1787 
1788     // default case => Float64Mod
1789     // For the left hand side we just propagate the identify zeros
1790     // mode of the {truncation}; and for modulus the sign of the
1791     // right hand side doesn't matter anyways, so in particular there's
1792     // no observable difference between a 0 and a -0 then.
1793     UseInfo const lhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1794         truncation.identify_zeros(), FeedbackSource());
1795     UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1796         kIdentifyZeros, FeedbackSource());
1797     VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
1798                   Type::Number());
1799     if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
1800     return;
1801   }
1802 
1803   // Just assert for Propagate and Retype. Lower specialized below.
1804   template <Phase T>
InsertUnreachableIfNecessary(Node * node)1805   void InsertUnreachableIfNecessary(Node* node) {
1806     static_assert(propagate<T>() || retype<T>(),
1807                   "This version of InsertUnreachableIfNecessary has to be "
1808                   "called in the Propagate or Retype phase.");
1809   }
1810 
1811   template <Phase T>
VisitCheckBounds(Node * node,SimplifiedLowering * lowering)1812   void VisitCheckBounds(Node* node, SimplifiedLowering* lowering) {
1813     CheckBoundsParameters const& p = CheckBoundsParametersOf(node->op());
1814     FeedbackSource const& feedback = p.check_parameters().feedback();
1815     Type const index_type = TypeOf(node->InputAt(0));
1816     Type const length_type = TypeOf(node->InputAt(1));
1817 
1818     // Conversions, if requested and needed, will be handled by the
1819     // representation changer, not by the lower-level Checked*Bounds operators.
1820     CheckBoundsFlags new_flags =
1821         p.flags().without(CheckBoundsFlag::kConvertStringAndMinusZero);
1822 
1823     if (length_type.Is(Type::Unsigned31())) {
1824       if (index_type.Is(Type::Integral32()) ||
1825           (index_type.Is(Type::Integral32OrMinusZero()) &&
1826            p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero)) {
1827         // Map the values in the [-2^31,-1] range to the [2^31,2^32-1] range,
1828         // which will be considered out-of-bounds because the {length_type} is
1829         // limited to Unsigned31. This also converts -0 to 0.
1830         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1831                       MachineRepresentation::kWord32);
1832         if (lower<T>()) {
1833           if (index_type.IsNone() || length_type.IsNone() ||
1834               (index_type.Min() >= 0.0 &&
1835                index_type.Max() < length_type.Min())) {
1836             // The bounds check is redundant if we already know that
1837             // the index is within the bounds of [0.0, length[.
1838             // TODO(neis): Move this into TypedOptimization?
1839             new_flags |= CheckBoundsFlag::kAbortOnOutOfBounds;
1840           }
1841           ChangeOp(node,
1842                    simplified()->CheckedUint32Bounds(feedback, new_flags));
1843         }
1844       } else if (p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero) {
1845         VisitBinop<T>(node, UseInfo::CheckedTaggedAsArrayIndex(feedback),
1846                       UseInfo::Word(), MachineType::PointerRepresentation());
1847         if (lower<T>()) {
1848           if (jsgraph_->machine()->Is64()) {
1849             ChangeOp(node,
1850                      simplified()->CheckedUint64Bounds(feedback, new_flags));
1851           } else {
1852             ChangeOp(node,
1853                      simplified()->CheckedUint32Bounds(feedback, new_flags));
1854           }
1855         }
1856       } else {
1857         VisitBinop<T>(
1858             node, UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, feedback),
1859             UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1860         if (lower<T>()) {
1861           ChangeOp(node,
1862                    simplified()->CheckedUint32Bounds(feedback, new_flags));
1863         }
1864       }
1865     } else {
1866       CHECK(length_type.Is(type_cache_->kPositiveSafeInteger));
1867       IdentifyZeros zero_handling =
1868           (p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero)
1869               ? kIdentifyZeros
1870               : kDistinguishZeros;
1871       VisitBinop<T>(node,
1872                     UseInfo::CheckedSigned64AsWord64(zero_handling, feedback),
1873                     UseInfo::Word64(), MachineRepresentation::kWord64);
1874       if (lower<T>()) {
1875         ChangeOp(node, simplified()->CheckedUint64Bounds(feedback, new_flags));
1876       }
1877     }
1878   }
1879 
UseInfoForFastApiCallArgument(CTypeInfo type,FeedbackSource const & feedback)1880   UseInfo UseInfoForFastApiCallArgument(CTypeInfo type,
1881                                         FeedbackSource const& feedback) {
1882     switch (type.GetSequenceType()) {
1883       case CTypeInfo::SequenceType::kScalar: {
1884         switch (type.GetType()) {
1885           case CTypeInfo::Type::kVoid:
1886             UNREACHABLE();
1887           case CTypeInfo::Type::kBool:
1888             return UseInfo::Bool();
1889           case CTypeInfo::Type::kInt32:
1890           case CTypeInfo::Type::kUint32:
1891             return UseInfo::CheckedNumberAsWord32(feedback);
1892           // TODO(mslekova): We deopt for unsafe integers, but ultimately we
1893           // want to make this less restrictive in order to stay on the fast
1894           // path.
1895           case CTypeInfo::Type::kInt64:
1896           case CTypeInfo::Type::kUint64:
1897           case CTypeInfo::Type::kAny:
1898             return UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, feedback);
1899           case CTypeInfo::Type::kFloat32:
1900           case CTypeInfo::Type::kFloat64:
1901             return UseInfo::CheckedNumberAsFloat64(kDistinguishZeros, feedback);
1902           case CTypeInfo::Type::kV8Value:
1903           case CTypeInfo::Type::kApiObject:
1904             return UseInfo::AnyTagged();
1905         }
1906       }
1907       case CTypeInfo::SequenceType::kIsSequence: {
1908         CHECK_EQ(type.GetType(), CTypeInfo::Type::kVoid);
1909         return UseInfo::AnyTagged();
1910       }
1911       case CTypeInfo::SequenceType::kIsTypedArray: {
1912         return UseInfo::AnyTagged();
1913       }
1914       default: {
1915         UNREACHABLE();  // TODO(mslekova): Implement array buffers.
1916       }
1917     }
1918   }
1919 
1920   static constexpr int kInitialArgumentsCount = 10;
1921 
1922   template <Phase T>
VisitFastApiCall(Node * node,SimplifiedLowering * lowering)1923   void VisitFastApiCall(Node* node, SimplifiedLowering* lowering) {
1924     FastApiCallParameters const& op_params =
1925         FastApiCallParametersOf(node->op());
1926     // We only consider the first function signature here. In case of function
1927     // overloads, we only support the case of two functions that differ for one
1928     // argument, which must be a JSArray in one function and a TypedArray in the
1929     // other function, and both JSArrays and TypedArrays have the same UseInfo
1930     // UseInfo::AnyTagged(). All the other argument types must match.
1931     const CFunctionInfo* c_signature = op_params.c_functions()[0].signature;
1932     const int c_arg_count = c_signature->ArgumentCount();
1933     CallDescriptor* call_descriptor = op_params.descriptor();
1934     int js_arg_count = static_cast<int>(call_descriptor->ParameterCount());
1935     const int value_input_count = node->op()->ValueInputCount();
1936     CHECK_EQ(FastApiCallNode::ArityForArgc(c_arg_count, js_arg_count),
1937              value_input_count);
1938 
1939     base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
1940         c_arg_count);
1941     // Propagate representation information from TypeInfo.
1942     for (int i = 0; i < c_arg_count; i++) {
1943       arg_use_info[i] = UseInfoForFastApiCallArgument(
1944           c_signature->ArgumentInfo(i), op_params.feedback());
1945       ProcessInput<T>(node, i, arg_use_info[i]);
1946     }
1947 
1948     // The call code for the slow call.
1949     ProcessInput<T>(node, c_arg_count, UseInfo::AnyTagged());
1950     for (int i = 1; i <= js_arg_count; i++) {
1951       ProcessInput<T>(node, c_arg_count + i,
1952                       TruncatingUseInfoFromRepresentation(
1953                           call_descriptor->GetInputType(i).representation()));
1954     }
1955     for (int i = c_arg_count + js_arg_count; i < value_input_count; ++i) {
1956       ProcessInput<T>(node, i, UseInfo::AnyTagged());
1957     }
1958     ProcessRemainingInputs<T>(node, value_input_count);
1959     SetOutput<T>(node, MachineRepresentation::kTagged);
1960   }
1961 
1962 #if V8_ENABLE_WEBASSEMBLY
MachineTypeForWasmReturnType(wasm::ValueType type)1963   static MachineType MachineTypeForWasmReturnType(wasm::ValueType type) {
1964     switch (type.kind()) {
1965       case wasm::kI32:
1966         return MachineType::Int32();
1967       case wasm::kF32:
1968         return MachineType::Float32();
1969       case wasm::kF64:
1970         return MachineType::Float64();
1971       case wasm::kI64:
1972         // Not used for i64, see VisitJSWasmCall().
1973       default:
1974         UNREACHABLE();
1975     }
1976   }
1977 
UseInfoForJSWasmCallArgument(Node * input,wasm::ValueType type,FeedbackSource const & feedback)1978   UseInfo UseInfoForJSWasmCallArgument(Node* input, wasm::ValueType type,
1979                                        FeedbackSource const& feedback) {
1980     // If the input type is a Number or Oddball, we can directly convert the
1981     // input into the Wasm native type of the argument. If not, we return
1982     // UseInfo::AnyTagged to signal that WasmWrapperGraphBuilder will need to
1983     // add Nodes to perform the conversion (in WasmWrapperGraphBuilder::FromJS).
1984     switch (type.kind()) {
1985       case wasm::kI32:
1986         return UseInfo::CheckedNumberOrOddballAsWord32(feedback);
1987       case wasm::kI64:
1988         return UseInfo::AnyTagged();
1989       case wasm::kF32:
1990       case wasm::kF64:
1991         // For Float32, TruncateFloat64ToFloat32 will be inserted later in
1992         // WasmWrapperGraphBuilder::BuildJSToWasmWrapper.
1993         return UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1994                                                         feedback);
1995       default:
1996         UNREACHABLE();
1997     }
1998   }
1999 
2000   template <Phase T>
VisitJSWasmCall(Node * node,SimplifiedLowering * lowering)2001   void VisitJSWasmCall(Node* node, SimplifiedLowering* lowering) {
2002     DCHECK_EQ(JSWasmCallNode::TargetIndex(), 0);
2003     DCHECK_EQ(JSWasmCallNode::ReceiverIndex(), 1);
2004     DCHECK_EQ(JSWasmCallNode::FirstArgumentIndex(), 2);
2005 
2006     JSWasmCallNode n(node);
2007 
2008     JSWasmCallParameters const& params = n.Parameters();
2009     const wasm::FunctionSig* wasm_signature = params.signature();
2010     int wasm_arg_count = static_cast<int>(wasm_signature->parameter_count());
2011     DCHECK_EQ(wasm_arg_count, n.ArgumentCount());
2012 
2013     base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
2014         wasm_arg_count);
2015 
2016     // Visit JSFunction and Receiver nodes.
2017     ProcessInput<T>(node, JSWasmCallNode::TargetIndex(), UseInfo::Any());
2018     ProcessInput<T>(node, JSWasmCallNode::ReceiverIndex(), UseInfo::Any());
2019 
2020     // Propagate representation information from TypeInfo.
2021     for (int i = 0; i < wasm_arg_count; i++) {
2022       TNode<Object> input = n.Argument(i);
2023       DCHECK_NOT_NULL(input);
2024       arg_use_info[i] = UseInfoForJSWasmCallArgument(
2025           input, wasm_signature->GetParam(i), params.feedback());
2026       ProcessInput<T>(node, JSWasmCallNode::ArgumentIndex(i), arg_use_info[i]);
2027     }
2028 
2029     // Visit value, context and frame state inputs as tagged.
2030     int first_effect_index = NodeProperties::FirstEffectIndex(node);
2031     DCHECK(first_effect_index >
2032            JSWasmCallNode::FirstArgumentIndex() + wasm_arg_count);
2033     for (int i = JSWasmCallNode::FirstArgumentIndex() + wasm_arg_count;
2034          i < first_effect_index; i++) {
2035       ProcessInput<T>(node, i, UseInfo::AnyTagged());
2036     }
2037 
2038     // Effect and Control.
2039     ProcessRemainingInputs<T>(node, NodeProperties::FirstEffectIndex(node));
2040 
2041     if (wasm_signature->return_count() == 1) {
2042       if (wasm_signature->GetReturn().kind() == wasm::kI64) {
2043         // Conversion between negative int64 and BigInt not supported yet.
2044         // Do not bypass the type conversion when the result type is i64.
2045         SetOutput<T>(node, MachineRepresentation::kTagged);
2046       } else {
2047         MachineType return_type =
2048             MachineTypeForWasmReturnType(wasm_signature->GetReturn());
2049         SetOutput<T>(
2050             node, return_type.representation(),
2051             JSWasmCallNode::TypeForWasmReturnType(wasm_signature->GetReturn()));
2052       }
2053     } else {
2054       DCHECK_EQ(wasm_signature->return_count(), 0);
2055       SetOutput<T>(node, MachineRepresentation::kTagged);
2056     }
2057 
2058     // The actual lowering of JSWasmCall nodes happens later, in the subsequent
2059     // "wasm-inlining" phase.
2060   }
2061 #endif  // V8_ENABLE_WEBASSEMBLY
2062 
2063   // Dispatching routine for visiting the node {node} with the usage {use}.
2064   // Depending on the operator, propagate new usage info to the inputs.
2065   template <Phase T>
VisitNode(Node * node,Truncation truncation,SimplifiedLowering * lowering)2066   void VisitNode(Node* node, Truncation truncation,
2067                  SimplifiedLowering* lowering) {
2068     tick_counter_->TickAndMaybeEnterSafepoint();
2069 
2070     if (lower<T>()) {
2071       // Kill non-effectful operations that have a None-type input and are thus
2072       // dead code. Otherwise we might end up lowering the operation in a way,
2073       // e.g. by replacing it with a constant, that cuts the dependency on a
2074       // deopting operation (the producer of the None type), possibly resulting
2075       // in a nonsense schedule.
2076       if (node->op()->EffectOutputCount() == 0 &&
2077           node->op()->ControlOutputCount() == 0 &&
2078           node->opcode() != IrOpcode::kDeadValue &&
2079           node->opcode() != IrOpcode::kStateValues &&
2080           node->opcode() != IrOpcode::kFrameState &&
2081           node->opcode() != IrOpcode::kPhi) {
2082         for (int i = 0; i < node->op()->ValueInputCount(); i++) {
2083           Node* input = node->InputAt(i);
2084           if (TypeOf(input).IsNone()) {
2085             node->ReplaceInput(0, input);
2086             node->TrimInputCount(1);
2087             ChangeOp(node,
2088                      common()->DeadValue(GetInfo(node)->representation()));
2089             return;
2090           }
2091         }
2092       } else {
2093         InsertUnreachableIfNecessary<T>(node);
2094       }
2095     }
2096 
2097     // Unconditionally eliminate unused pure nodes (only relevant if there's
2098     // a pure operation in between two effectful ones, where the last one
2099     // is unused).
2100     // Note: We must not do this for constants, as they are cached and we
2101     // would thus kill the cached {node} during lowering (i.e. replace all
2102     // uses with Dead), but at that point some node lowering might have
2103     // already taken the constant {node} from the cache (while it was not
2104     // yet killed) and we would afterwards replace that use with Dead as well.
2105     if (node->op()->ValueInputCount() > 0 &&
2106         node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) {
2107       return VisitUnused<T>(node);
2108     }
2109 
2110     switch (node->opcode()) {
2111       //------------------------------------------------------------------
2112       // Common operators.
2113       //------------------------------------------------------------------
2114       case IrOpcode::kStart:
2115         // We use Start as a terminator for the frame state chain, so even
2116         // tho Start doesn't really produce a value, we have to say Tagged
2117         // here, otherwise the input conversion will fail.
2118         return VisitLeaf<T>(node, MachineRepresentation::kTagged);
2119       case IrOpcode::kParameter:
2120         return VisitUnop<T>(node, UseInfo::None(),
2121                             linkage()
2122                                 ->GetParameterType(ParameterIndexOf(node->op()))
2123                                 .representation());
2124       case IrOpcode::kInt32Constant:
2125         return VisitLeaf<T>(node, MachineRepresentation::kWord32);
2126       case IrOpcode::kInt64Constant:
2127         return VisitLeaf<T>(node, MachineRepresentation::kWord64);
2128       case IrOpcode::kExternalConstant:
2129         return VisitLeaf<T>(node, MachineType::PointerRepresentation());
2130       case IrOpcode::kNumberConstant: {
2131         double const value = OpParameter<double>(node->op());
2132         int value_as_int;
2133         if (DoubleToSmiInteger(value, &value_as_int)) {
2134           VisitLeaf<T>(node, MachineRepresentation::kTaggedSigned);
2135           if (lower<T>()) {
2136             intptr_t smi = bit_cast<intptr_t>(Smi::FromInt(value_as_int));
2137             Node* constant = InsertTypeOverrideForVerifier(
2138                 NodeProperties::GetType(node),
2139                 lowering->jsgraph()->IntPtrConstant(smi));
2140             DeferReplacement(node, constant);
2141           }
2142           return;
2143         }
2144         VisitLeaf<T>(node, MachineRepresentation::kTagged);
2145         return;
2146       }
2147       case IrOpcode::kHeapConstant:
2148       case IrOpcode::kDelayedStringConstant:
2149         return VisitLeaf<T>(node, MachineRepresentation::kTaggedPointer);
2150       case IrOpcode::kPointerConstant: {
2151         VisitLeaf<T>(node, MachineType::PointerRepresentation());
2152         if (lower<T>()) {
2153           intptr_t const value = OpParameter<intptr_t>(node->op());
2154           DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
2155         }
2156         return;
2157       }
2158 
2159       case IrOpcode::kBranch: {
2160         DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
2161         ProcessInput<T>(node, 0, UseInfo::Bool());
2162         EnqueueInput<T>(node, NodeProperties::FirstControlIndex(node));
2163         return;
2164       }
2165       case IrOpcode::kSwitch:
2166         ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());
2167         EnqueueInput<T>(node, NodeProperties::FirstControlIndex(node));
2168         return;
2169       case IrOpcode::kSelect:
2170         return VisitSelect<T>(node, truncation, lowering);
2171       case IrOpcode::kPhi:
2172         return VisitPhi<T>(node, truncation, lowering);
2173       case IrOpcode::kCall:
2174         return VisitCall<T>(node, lowering);
2175 
2176       //------------------------------------------------------------------
2177       // JavaScript operators.
2178       //------------------------------------------------------------------
2179       case IrOpcode::kJSToNumber:
2180       case IrOpcode::kJSToNumberConvertBigInt:
2181       case IrOpcode::kJSToNumeric: {
2182         DCHECK(NodeProperties::GetType(node).Is(Type::Union(
2183             Type::BigInt(), Type::NumberOrOddball(), graph()->zone())));
2184         VisitInputs<T>(node);
2185         // TODO(bmeurer): Optimize somewhat based on input type?
2186         if (truncation.IsUsedAsWord32()) {
2187           SetOutput<T>(node, MachineRepresentation::kWord32);
2188           if (lower<T>())
2189             lowering->DoJSToNumberOrNumericTruncatesToWord32(node, this);
2190         } else if (truncation.TruncatesOddballAndBigIntToNumber()) {
2191           SetOutput<T>(node, MachineRepresentation::kFloat64);
2192           if (lower<T>())
2193             lowering->DoJSToNumberOrNumericTruncatesToFloat64(node, this);
2194         } else {
2195           SetOutput<T>(node, MachineRepresentation::kTagged);
2196         }
2197         return;
2198       }
2199 
2200       //------------------------------------------------------------------
2201       // Simplified operators.
2202       //------------------------------------------------------------------
2203       case IrOpcode::kToBoolean: {
2204         if (truncation.IsUsedAsBool()) {
2205           ProcessInput<T>(node, 0, UseInfo::Bool());
2206           SetOutput<T>(node, MachineRepresentation::kBit);
2207           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2208         } else {
2209           VisitInputs<T>(node);
2210           SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
2211         }
2212         return;
2213       }
2214       case IrOpcode::kBooleanNot: {
2215         if (lower<T>()) {
2216           NodeInfo* input_info = GetInfo(node->InputAt(0));
2217           if (input_info->representation() == MachineRepresentation::kBit) {
2218             // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
2219             node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
2220             ChangeOp(node, lowering->machine()->Word32Equal());
2221           } else if (CanBeTaggedPointer(input_info->representation())) {
2222             // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
2223             node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
2224             ChangeOp(node, lowering->machine()->WordEqual());
2225           } else {
2226             DCHECK(TypeOf(node->InputAt(0)).IsNone());
2227             DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
2228           }
2229         } else {
2230           // No input representation requirement; adapt during lowering.
2231           ProcessInput<T>(node, 0, UseInfo::AnyTruncatingToBool());
2232           SetOutput<T>(node, MachineRepresentation::kBit);
2233         }
2234         return;
2235       }
2236       case IrOpcode::kNumberEqual: {
2237         Type const lhs_type = TypeOf(node->InputAt(0));
2238         Type const rhs_type = TypeOf(node->InputAt(1));
2239         // Regular number comparisons in JavaScript generally identify zeros,
2240         // so we always pass kIdentifyZeros for the inputs, and in addition
2241         // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
2242         // For equality we also handle the case that one side is non-zero, in
2243         // which case we allow to truncate NaN to 0 on the other side.
2244         if ((lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2245              rhs_type.Is(Type::Unsigned32OrMinusZero())) ||
2246             (lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2247              rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2248              OneInputCannotBe(node, type_cache_->kZeroish))) {
2249           // => unsigned Int32Cmp
2250           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2251                         MachineRepresentation::kBit);
2252           if (lower<T>()) ChangeOp(node, Uint32Op(node));
2253           return;
2254         }
2255         if ((lhs_type.Is(Type::Signed32OrMinusZero()) &&
2256              rhs_type.Is(Type::Signed32OrMinusZero())) ||
2257             (lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2258              rhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2259              OneInputCannotBe(node, type_cache_->kZeroish))) {
2260           // => signed Int32Cmp
2261           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2262                         MachineRepresentation::kBit);
2263           if (lower<T>()) ChangeOp(node, Int32Op(node));
2264           return;
2265         }
2266         // => Float64Cmp
2267         VisitBinop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2268                       MachineRepresentation::kBit);
2269         if (lower<T>()) ChangeOp(node, Float64Op(node));
2270         return;
2271       }
2272       case IrOpcode::kNumberLessThan:
2273       case IrOpcode::kNumberLessThanOrEqual: {
2274         Type const lhs_type = TypeOf(node->InputAt(0));
2275         Type const rhs_type = TypeOf(node->InputAt(1));
2276         // Regular number comparisons in JavaScript generally identify zeros,
2277         // so we always pass kIdentifyZeros for the inputs, and in addition
2278         // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
2279         if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2280             rhs_type.Is(Type::Unsigned32OrMinusZero())) {
2281           // => unsigned Int32Cmp
2282           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2283                         MachineRepresentation::kBit);
2284           if (lower<T>()) ChangeOp(node, Uint32Op(node));
2285         } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2286                    rhs_type.Is(Type::Signed32OrMinusZero())) {
2287           // => signed Int32Cmp
2288           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2289                         MachineRepresentation::kBit);
2290           if (lower<T>()) ChangeOp(node, Int32Op(node));
2291         } else {
2292           // => Float64Cmp
2293           VisitBinop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2294                         MachineRepresentation::kBit);
2295           if (lower<T>()) ChangeOp(node, Float64Op(node));
2296         }
2297         return;
2298       }
2299 
2300       case IrOpcode::kSpeculativeSafeIntegerAdd:
2301       case IrOpcode::kSpeculativeSafeIntegerSubtract:
2302         return VisitSpeculativeIntegerAdditiveOp<T>(node, truncation, lowering);
2303 
2304       case IrOpcode::kSpeculativeNumberAdd:
2305       case IrOpcode::kSpeculativeNumberSubtract:
2306         return VisitSpeculativeAdditiveOp<T>(node, truncation, lowering);
2307 
2308       case IrOpcode::kSpeculativeNumberLessThan:
2309       case IrOpcode::kSpeculativeNumberLessThanOrEqual:
2310       case IrOpcode::kSpeculativeNumberEqual: {
2311         Type const lhs_type = TypeOf(node->InputAt(0));
2312         Type const rhs_type = TypeOf(node->InputAt(1));
2313         // Regular number comparisons in JavaScript generally identify zeros,
2314         // so we always pass kIdentifyZeros for the inputs, and in addition
2315         // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
2316         if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2317             rhs_type.Is(Type::Unsigned32OrMinusZero())) {
2318           // => unsigned Int32Cmp
2319           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2320                         MachineRepresentation::kBit);
2321           if (lower<T>()) ChangeToPureOp(node, Uint32Op(node));
2322           return;
2323         } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2324                    rhs_type.Is(Type::Signed32OrMinusZero())) {
2325           // => signed Int32Cmp
2326           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2327                         MachineRepresentation::kBit);
2328           if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2329           return;
2330         }
2331         // Try to use type feedback.
2332         NumberOperationHint hint = NumberOperationHintOf(node->op());
2333         switch (hint) {
2334           case NumberOperationHint::kSignedSmall:
2335             if (propagate<T>()) {
2336               VisitBinop<T>(
2337                   node, CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2338                   MachineRepresentation::kBit);
2339             } else if (retype<T>()) {
2340               SetOutput<T>(node, MachineRepresentation::kBit, Type::Any());
2341             } else {
2342               DCHECK(lower<T>());
2343               Node* lhs = node->InputAt(0);
2344               Node* rhs = node->InputAt(1);
2345               if (IsNodeRepresentationTagged(lhs) &&
2346                   IsNodeRepresentationTagged(rhs)) {
2347                 VisitBinop<T>(node,
2348                               UseInfo::CheckedSignedSmallAsTaggedSigned(
2349                                   FeedbackSource(), kIdentifyZeros),
2350                               MachineRepresentation::kBit);
2351                 ChangeToPureOp(
2352                     node, changer_->TaggedSignedOperatorFor(node->opcode()));
2353 
2354               } else {
2355                 VisitBinop<T>(
2356                     node, CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2357                     MachineRepresentation::kBit);
2358                 ChangeToPureOp(node, Int32Op(node));
2359               }
2360             }
2361             return;
2362           case NumberOperationHint::kSignedSmallInputs:
2363             // This doesn't make sense for compare operations.
2364             UNREACHABLE();
2365           case NumberOperationHint::kNumberOrOddball:
2366             // Abstract and strict equality don't perform ToNumber conversions
2367             // on Oddballs, so make sure we don't accidentially sneak in a
2368             // hint with Oddball feedback here.
2369             DCHECK_NE(IrOpcode::kSpeculativeNumberEqual, node->opcode());
2370             V8_FALLTHROUGH;
2371           case NumberOperationHint::kNumberOrBoolean:
2372           case NumberOperationHint::kNumber:
2373             VisitBinop<T>(node,
2374                           CheckedUseInfoAsFloat64FromHint(
2375                               hint, FeedbackSource(), kIdentifyZeros),
2376                           MachineRepresentation::kBit);
2377             if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2378             return;
2379         }
2380         UNREACHABLE();
2381         return;
2382       }
2383 
2384       case IrOpcode::kNumberAdd:
2385       case IrOpcode::kNumberSubtract: {
2386         if (TypeOf(node->InputAt(0))
2387                 .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
2388             TypeOf(node->InputAt(1))
2389                 .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
2390             (TypeOf(node).Is(Type::Signed32()) ||
2391              TypeOf(node).Is(Type::Unsigned32()) ||
2392              truncation.IsUsedAsWord32())) {
2393           // => Int32Add/Sub
2394           VisitWord32TruncatingBinop<T>(node);
2395           if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2396         } else if (jsgraph_->machine()->Is64() &&
2397                    BothInputsAre(node, type_cache_->kSafeInteger) &&
2398                    GetUpperBound(node).Is(type_cache_->kSafeInteger)) {
2399           // => Int64Add/Sub
2400           VisitInt64Binop<T>(node);
2401           if (lower<T>()) ChangeToPureOp(node, Int64Op(node));
2402         } else {
2403           // => Float64Add/Sub
2404           VisitFloat64Binop<T>(node);
2405           if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2406         }
2407         return;
2408       }
2409       case IrOpcode::kSpeculativeNumberMultiply: {
2410         if (BothInputsAre(node, Type::Integral32()) &&
2411             (NodeProperties::GetType(node).Is(Type::Signed32()) ||
2412              NodeProperties::GetType(node).Is(Type::Unsigned32()) ||
2413              (truncation.IsUsedAsWord32() &&
2414               NodeProperties::GetType(node).Is(
2415                   type_cache_->kSafeIntegerOrMinusZero)))) {
2416           // Multiply reduces to Int32Mul if the inputs are integers, and
2417           // (a) the output is either known to be Signed32, or
2418           // (b) the output is known to be Unsigned32, or
2419           // (c) the uses are truncating and the result is in the safe
2420           //     integer range.
2421           VisitWord32TruncatingBinop<T>(node);
2422           if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2423           return;
2424         }
2425         // Try to use type feedback.
2426         NumberOperationHint hint = NumberOperationHintOf(node->op());
2427         Type input0_type = TypeOf(node->InputAt(0));
2428         Type input1_type = TypeOf(node->InputAt(1));
2429 
2430         // Handle the case when no int32 checks on inputs are necessary
2431         // (but an overflow check is needed on the output).
2432         if (BothInputsAre(node, Type::Signed32())) {
2433           // If both inputs and feedback are int32, use the overflow op.
2434           if (hint == NumberOperationHint::kSignedSmall) {
2435             VisitForCheckedInt32Mul<T>(node, truncation, input0_type,
2436                                        input1_type,
2437                                        UseInfo::TruncatingWord32());
2438             return;
2439           }
2440         }
2441 
2442         if (hint == NumberOperationHint::kSignedSmall) {
2443           VisitForCheckedInt32Mul<T>(node, truncation, input0_type, input1_type,
2444                                      CheckedUseInfoAsWord32FromHint(hint));
2445           return;
2446         }
2447 
2448         // Checked float64 x float64 => float64
2449         VisitBinop<T>(node,
2450                       UseInfo::CheckedNumberOrOddballAsFloat64(
2451                           kDistinguishZeros, FeedbackSource()),
2452                       MachineRepresentation::kFloat64, Type::Number());
2453         if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2454         return;
2455       }
2456       case IrOpcode::kNumberMultiply: {
2457         if (TypeOf(node->InputAt(0)).Is(Type::Integral32()) &&
2458             TypeOf(node->InputAt(1)).Is(Type::Integral32()) &&
2459             (TypeOf(node).Is(Type::Signed32()) ||
2460              TypeOf(node).Is(Type::Unsigned32()) ||
2461              (truncation.IsUsedAsWord32() &&
2462               TypeOf(node).Is(type_cache_->kSafeIntegerOrMinusZero)))) {
2463           // Multiply reduces to Int32Mul if the inputs are integers, and
2464           // (a) the output is either known to be Signed32, or
2465           // (b) the output is known to be Unsigned32, or
2466           // (c) the uses are truncating and the result is in the safe
2467           //     integer range.
2468           VisitWord32TruncatingBinop<T>(node);
2469           if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2470           return;
2471         }
2472         // Number x Number => Float64Mul
2473         VisitFloat64Binop<T>(node);
2474         if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2475         return;
2476       }
2477       case IrOpcode::kSpeculativeNumberDivide: {
2478         if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
2479           // => unsigned Uint32Div
2480           VisitWord32TruncatingBinop<T>(node);
2481           if (lower<T>()) DeferReplacement(node, lowering->Uint32Div(node));
2482           return;
2483         }
2484         if (BothInputsAreSigned32(node)) {
2485           if (NodeProperties::GetType(node).Is(Type::Signed32())) {
2486             // => signed Int32Div
2487             VisitWord32TruncatingBinop<T>(node);
2488             if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2489             return;
2490           }
2491           if (truncation.IsUsedAsWord32()) {
2492             // => signed Int32Div
2493             VisitWord32TruncatingBinop<T>(node);
2494             if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2495             return;
2496           }
2497         }
2498 
2499         // Try to use type feedback.
2500         NumberOperationHint hint = NumberOperationHintOf(node->op());
2501 
2502         // Handle the case when no uint32 checks on inputs are necessary
2503         // (but an overflow check is needed on the output).
2504         if (BothInputsAreUnsigned32(node)) {
2505           if (hint == NumberOperationHint::kSignedSmall) {
2506             VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2507                           MachineRepresentation::kWord32, Type::Unsigned32());
2508             if (lower<T>()) ChangeToUint32OverflowOp(node);
2509             return;
2510           }
2511         }
2512 
2513         // Handle the case when no int32 checks on inputs are necessary
2514         // (but an overflow check is needed on the output).
2515         if (BothInputsAreSigned32(node)) {
2516           // If both the inputs the feedback are int32, use the overflow op.
2517           if (hint == NumberOperationHint::kSignedSmall) {
2518             VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2519                           MachineRepresentation::kWord32, Type::Signed32());
2520             if (lower<T>()) ChangeToInt32OverflowOp(node);
2521             return;
2522           }
2523         }
2524 
2525         if (hint == NumberOperationHint::kSignedSmall ||
2526             hint == NumberOperationHint::kSignedSmallInputs) {
2527           // If the result is truncated, we only need to check the inputs.
2528           if (truncation.IsUsedAsWord32()) {
2529             VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
2530                           MachineRepresentation::kWord32);
2531             if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2532             return;
2533           } else if (hint != NumberOperationHint::kSignedSmallInputs) {
2534             VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
2535                           MachineRepresentation::kWord32, Type::Signed32());
2536             if (lower<T>()) ChangeToInt32OverflowOp(node);
2537             return;
2538           }
2539         }
2540 
2541         // default case => Float64Div
2542         VisitBinop<T>(node,
2543                       UseInfo::CheckedNumberOrOddballAsFloat64(
2544                           kDistinguishZeros, FeedbackSource()),
2545                       MachineRepresentation::kFloat64, Type::Number());
2546         if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2547         return;
2548       }
2549       case IrOpcode::kNumberDivide: {
2550         if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
2551             TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
2552             (truncation.IsUsedAsWord32() ||
2553              TypeOf(node).Is(Type::Unsigned32()))) {
2554           // => unsigned Uint32Div
2555           VisitWord32TruncatingBinop<T>(node);
2556           if (lower<T>()) DeferReplacement(node, lowering->Uint32Div(node));
2557           return;
2558         }
2559         if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
2560             TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
2561             (truncation.IsUsedAsWord32() ||
2562              TypeOf(node).Is(Type::Signed32()))) {
2563           // => signed Int32Div
2564           VisitWord32TruncatingBinop<T>(node);
2565           if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2566           return;
2567         }
2568         // Number x Number => Float64Div
2569         VisitFloat64Binop<T>(node);
2570         if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2571         return;
2572       }
2573       case IrOpcode::kSpeculativeNumberModulus:
2574         return VisitSpeculativeNumberModulus<T>(node, truncation, lowering);
2575       case IrOpcode::kNumberModulus: {
2576         Type const lhs_type = TypeOf(node->InputAt(0));
2577         Type const rhs_type = TypeOf(node->InputAt(1));
2578         if ((lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2579              rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) &&
2580             (truncation.IsUsedAsWord32() ||
2581              TypeOf(node).Is(Type::Unsigned32()))) {
2582           // => unsigned Uint32Mod
2583           VisitWord32TruncatingBinop<T>(node);
2584           if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
2585           return;
2586         }
2587         if ((lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2588              rhs_type.Is(Type::Signed32OrMinusZeroOrNaN())) &&
2589             (truncation.IsUsedAsWord32() || TypeOf(node).Is(Type::Signed32()) ||
2590              (truncation.IdentifiesZeroAndMinusZero() &&
2591               TypeOf(node).Is(Type::Signed32OrMinusZero())))) {
2592           // => signed Int32Mod
2593           VisitWord32TruncatingBinop<T>(node);
2594           if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
2595           return;
2596         }
2597         // => Float64Mod
2598         // For the left hand side we just propagate the identify zeros
2599         // mode of the {truncation}; and for modulus the sign of the
2600         // right hand side doesn't matter anyways, so in particular there's
2601         // no observable difference between a 0 and a -0 then.
2602         UseInfo const lhs_use =
2603             UseInfo::TruncatingFloat64(truncation.identify_zeros());
2604         UseInfo const rhs_use = UseInfo::TruncatingFloat64(kIdentifyZeros);
2605         VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kFloat64);
2606         if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2607         return;
2608       }
2609       case IrOpcode::kNumberBitwiseOr:
2610       case IrOpcode::kNumberBitwiseXor:
2611       case IrOpcode::kNumberBitwiseAnd: {
2612         VisitWord32TruncatingBinop<T>(node);
2613         if (lower<T>()) ChangeOp(node, Int32Op(node));
2614         return;
2615       }
2616       case IrOpcode::kSpeculativeNumberBitwiseOr:
2617       case IrOpcode::kSpeculativeNumberBitwiseXor:
2618       case IrOpcode::kSpeculativeNumberBitwiseAnd:
2619         VisitSpeculativeInt32Binop<T>(node);
2620         if (lower<T>()) {
2621           ChangeToPureOp(node, Int32Op(node));
2622         }
2623         return;
2624       case IrOpcode::kNumberShiftLeft: {
2625         Type rhs_type = GetUpperBound(node->InputAt(1));
2626         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2627                       UseInfo::TruncatingWord32(),
2628                       MachineRepresentation::kWord32);
2629         if (lower<T>()) {
2630           MaskShiftOperand(node, rhs_type);
2631           ChangeToPureOp(node, lowering->machine()->Word32Shl());
2632         }
2633         return;
2634       }
2635       case IrOpcode::kSpeculativeNumberShiftLeft: {
2636         if (BothInputsAre(node, Type::NumberOrOddball())) {
2637           Type rhs_type = GetUpperBound(node->InputAt(1));
2638           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2639                         UseInfo::TruncatingWord32(),
2640                         MachineRepresentation::kWord32);
2641           if (lower<T>()) {
2642             MaskShiftOperand(node, rhs_type);
2643             ChangeToPureOp(node, lowering->machine()->Word32Shl());
2644           }
2645           return;
2646         }
2647         NumberOperationHint hint = NumberOperationHintOf(node->op());
2648         Type rhs_type = GetUpperBound(node->InputAt(1));
2649         VisitBinop<T>(node,
2650                       CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2651                       MachineRepresentation::kWord32, Type::Signed32());
2652         if (lower<T>()) {
2653           MaskShiftOperand(node, rhs_type);
2654           ChangeToPureOp(node, lowering->machine()->Word32Shl());
2655         }
2656         return;
2657       }
2658       case IrOpcode::kNumberShiftRight: {
2659         Type rhs_type = GetUpperBound(node->InputAt(1));
2660         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2661                       UseInfo::TruncatingWord32(),
2662                       MachineRepresentation::kWord32);
2663         if (lower<T>()) {
2664           MaskShiftOperand(node, rhs_type);
2665           ChangeToPureOp(node, lowering->machine()->Word32Sar());
2666         }
2667         return;
2668       }
2669       case IrOpcode::kSpeculativeNumberShiftRight: {
2670         if (BothInputsAre(node, Type::NumberOrOddball())) {
2671           Type rhs_type = GetUpperBound(node->InputAt(1));
2672           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2673                         UseInfo::TruncatingWord32(),
2674                         MachineRepresentation::kWord32);
2675           if (lower<T>()) {
2676             MaskShiftOperand(node, rhs_type);
2677             ChangeToPureOp(node, lowering->machine()->Word32Sar());
2678           }
2679           return;
2680         }
2681         NumberOperationHint hint = NumberOperationHintOf(node->op());
2682         Type rhs_type = GetUpperBound(node->InputAt(1));
2683         VisitBinop<T>(node,
2684                       CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2685                       MachineRepresentation::kWord32, Type::Signed32());
2686         if (lower<T>()) {
2687           MaskShiftOperand(node, rhs_type);
2688           ChangeToPureOp(node, lowering->machine()->Word32Sar());
2689         }
2690         return;
2691       }
2692       case IrOpcode::kNumberShiftRightLogical: {
2693         Type rhs_type = GetUpperBound(node->InputAt(1));
2694         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2695                       UseInfo::TruncatingWord32(),
2696                       MachineRepresentation::kWord32);
2697         if (lower<T>()) {
2698           MaskShiftOperand(node, rhs_type);
2699           ChangeToPureOp(node, lowering->machine()->Word32Shr());
2700         }
2701         return;
2702       }
2703       case IrOpcode::kSpeculativeNumberShiftRightLogical: {
2704         NumberOperationHint hint = NumberOperationHintOf(node->op());
2705         Type rhs_type = GetUpperBound(node->InputAt(1));
2706         if (rhs_type.Is(type_cache_->kZeroish) &&
2707             hint == NumberOperationHint::kSignedSmall &&
2708             !truncation.IsUsedAsWord32()) {
2709           // The SignedSmall or Signed32 feedback means that the results that we
2710           // have seen so far were of type Unsigned31.  We speculate that this
2711           // will continue to hold.  Moreover, since the RHS is 0, the result
2712           // will just be the (converted) LHS.
2713           VisitBinop<T>(node,
2714                         CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2715                         MachineRepresentation::kWord32, Type::Unsigned31());
2716           if (lower<T>()) {
2717             node->RemoveInput(1);
2718             ChangeOp(node,
2719                      simplified()->CheckedUint32ToInt32(FeedbackSource()));
2720           }
2721           return;
2722         }
2723         if (BothInputsAre(node, Type::NumberOrOddball())) {
2724           VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2725                         UseInfo::TruncatingWord32(),
2726                         MachineRepresentation::kWord32);
2727           if (lower<T>()) {
2728             MaskShiftOperand(node, rhs_type);
2729             ChangeToPureOp(node, lowering->machine()->Word32Shr());
2730           }
2731           return;
2732         }
2733         VisitBinop<T>(node,
2734                       CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2735                       MachineRepresentation::kWord32, Type::Unsigned32());
2736         if (lower<T>()) {
2737           MaskShiftOperand(node, rhs_type);
2738           ChangeToPureOp(node, lowering->machine()->Word32Shr());
2739         }
2740         return;
2741       }
2742       case IrOpcode::kNumberAbs: {
2743         // NumberAbs maps both 0 and -0 to 0, so we can generally
2744         // pass the kIdentifyZeros truncation to its input, and
2745         // choose to ignore minus zero in all cases.
2746         Type const input_type = TypeOf(node->InputAt(0));
2747         if (input_type.Is(Type::Unsigned32OrMinusZero())) {
2748           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
2749                        MachineRepresentation::kWord32);
2750           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2751         } else if (input_type.Is(Type::Signed32OrMinusZero())) {
2752           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
2753                        MachineRepresentation::kWord32);
2754           if (lower<T>()) DeferReplacement(node, lowering->Int32Abs(node));
2755         } else if (input_type.Is(type_cache_->kPositiveIntegerOrNaN)) {
2756           VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2757                        MachineRepresentation::kFloat64);
2758           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2759         } else {
2760           VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2761                        MachineRepresentation::kFloat64);
2762           if (lower<T>()) ChangeOp(node, Float64Op(node));
2763         }
2764         return;
2765       }
2766       case IrOpcode::kNumberClz32: {
2767         VisitUnop<T>(node, UseInfo::TruncatingWord32(),
2768                      MachineRepresentation::kWord32);
2769         if (lower<T>()) ChangeOp(node, Uint32Op(node));
2770         return;
2771       }
2772       case IrOpcode::kNumberImul: {
2773         VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2774                       UseInfo::TruncatingWord32(),
2775                       MachineRepresentation::kWord32);
2776         if (lower<T>()) ChangeOp(node, Uint32Op(node));
2777         return;
2778       }
2779       case IrOpcode::kNumberFround: {
2780         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
2781                      MachineRepresentation::kFloat32);
2782         if (lower<T>()) ChangeOp(node, Float64Op(node));
2783         return;
2784       }
2785       case IrOpcode::kNumberMax: {
2786         // It is safe to use the feedback types for left and right hand side
2787         // here, since we can only narrow those types and thus we can only
2788         // promise a more specific truncation.
2789         // For NumberMax we generally propagate whether the truncation
2790         // identifies zeros to the inputs, and we choose to ignore minus
2791         // zero in those cases.
2792         Type const lhs_type = TypeOf(node->InputAt(0));
2793         Type const rhs_type = TypeOf(node->InputAt(1));
2794         if ((lhs_type.Is(Type::Unsigned32()) &&
2795              rhs_type.Is(Type::Unsigned32())) ||
2796             (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2797              rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2798              truncation.IdentifiesZeroAndMinusZero())) {
2799           VisitWord32TruncatingBinop<T>(node);
2800           if (lower<T>()) {
2801             lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
2802                             MachineRepresentation::kWord32);
2803           }
2804         } else if ((lhs_type.Is(Type::Signed32()) &&
2805                     rhs_type.Is(Type::Signed32())) ||
2806                    (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2807                     rhs_type.Is(Type::Signed32OrMinusZero()) &&
2808                     truncation.IdentifiesZeroAndMinusZero())) {
2809           VisitWord32TruncatingBinop<T>(node);
2810           if (lower<T>()) {
2811             lowering->DoMax(node, lowering->machine()->Int32LessThan(),
2812                             MachineRepresentation::kWord32);
2813           }
2814         } else if (jsgraph_->machine()->Is64() &&
2815                    lhs_type.Is(type_cache_->kSafeInteger) &&
2816                    rhs_type.Is(type_cache_->kSafeInteger)) {
2817           VisitInt64Binop<T>(node);
2818           if (lower<T>()) {
2819             lowering->DoMax(node, lowering->machine()->Int64LessThan(),
2820                             MachineRepresentation::kWord64);
2821           }
2822         } else {
2823           VisitBinop<T>(node,
2824                         UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2825                         MachineRepresentation::kFloat64);
2826           if (lower<T>()) {
2827             // If the right hand side is not NaN, and the left hand side
2828             // is not NaN (or -0 if the difference between the zeros is
2829             // observed), we can do a simple floating point comparison here.
2830             if (lhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2831                                 ? Type::OrderedNumber()
2832                                 : Type::PlainNumber()) &&
2833                 rhs_type.Is(Type::OrderedNumber())) {
2834               lowering->DoMax(node, lowering->machine()->Float64LessThan(),
2835                               MachineRepresentation::kFloat64);
2836             } else {
2837               ChangeOp(node, Float64Op(node));
2838             }
2839           }
2840         }
2841         return;
2842       }
2843       case IrOpcode::kNumberMin: {
2844         // It is safe to use the feedback types for left and right hand side
2845         // here, since we can only narrow those types and thus we can only
2846         // promise a more specific truncation.
2847         // For NumberMin we generally propagate whether the truncation
2848         // identifies zeros to the inputs, and we choose to ignore minus
2849         // zero in those cases.
2850         Type const lhs_type = TypeOf(node->InputAt(0));
2851         Type const rhs_type = TypeOf(node->InputAt(1));
2852         if ((lhs_type.Is(Type::Unsigned32()) &&
2853              rhs_type.Is(Type::Unsigned32())) ||
2854             (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2855              rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2856              truncation.IdentifiesZeroAndMinusZero())) {
2857           VisitWord32TruncatingBinop<T>(node);
2858           if (lower<T>()) {
2859             lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
2860                             MachineRepresentation::kWord32);
2861           }
2862         } else if ((lhs_type.Is(Type::Signed32()) &&
2863                     rhs_type.Is(Type::Signed32())) ||
2864                    (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2865                     rhs_type.Is(Type::Signed32OrMinusZero()) &&
2866                     truncation.IdentifiesZeroAndMinusZero())) {
2867           VisitWord32TruncatingBinop<T>(node);
2868           if (lower<T>()) {
2869             lowering->DoMin(node, lowering->machine()->Int32LessThan(),
2870                             MachineRepresentation::kWord32);
2871           }
2872         } else if (jsgraph_->machine()->Is64() &&
2873                    lhs_type.Is(type_cache_->kSafeInteger) &&
2874                    rhs_type.Is(type_cache_->kSafeInteger)) {
2875           VisitInt64Binop<T>(node);
2876           if (lower<T>()) {
2877             lowering->DoMin(node, lowering->machine()->Int64LessThan(),
2878                             MachineRepresentation::kWord64);
2879           }
2880         } else {
2881           VisitBinop<T>(node,
2882                         UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2883                         MachineRepresentation::kFloat64);
2884           if (lower<T>()) {
2885             // If the left hand side is not NaN, and the right hand side
2886             // is not NaN (or -0 if the difference between the zeros is
2887             // observed), we can do a simple floating point comparison here.
2888             if (lhs_type.Is(Type::OrderedNumber()) &&
2889                 rhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2890                                 ? Type::OrderedNumber()
2891                                 : Type::PlainNumber())) {
2892               lowering->DoMin(node,
2893                               lowering->machine()->Float64LessThanOrEqual(),
2894                               MachineRepresentation::kFloat64);
2895             } else {
2896               ChangeOp(node, Float64Op(node));
2897             }
2898           }
2899         }
2900         return;
2901       }
2902       case IrOpcode::kSpeculativeNumberPow: {
2903         // Checked float64 ** float64 => float64
2904         VisitBinop<T>(node,
2905                       UseInfo::CheckedNumberOrOddballAsFloat64(
2906                           kDistinguishZeros, FeedbackSource()),
2907                       MachineRepresentation::kFloat64, Type::Number());
2908         if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2909         return;
2910       }
2911       case IrOpcode::kNumberAtan2:
2912       case IrOpcode::kNumberPow: {
2913         VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
2914                       MachineRepresentation::kFloat64);
2915         if (lower<T>()) ChangeOp(node, Float64Op(node));
2916         return;
2917       }
2918       case IrOpcode::kNumberCeil:
2919       case IrOpcode::kNumberFloor:
2920       case IrOpcode::kNumberRound:
2921       case IrOpcode::kNumberTrunc: {
2922         // For NumberCeil, NumberFloor, NumberRound and NumberTrunc we propagate
2923         // the zero identification part of the truncation, and we turn them into
2924         // no-ops if we figure out (late) that their input is already an
2925         // integer, NaN or -0.
2926         Type const input_type = TypeOf(node->InputAt(0));
2927         VisitUnop<T>(node,
2928                      UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2929                      MachineRepresentation::kFloat64);
2930         if (lower<T>()) {
2931           if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2932             DeferReplacement(node, node->InputAt(0));
2933           } else if (node->opcode() == IrOpcode::kNumberRound) {
2934             DeferReplacement(node, lowering->Float64Round(node));
2935           } else {
2936             ChangeOp(node, Float64Op(node));
2937           }
2938         }
2939         return;
2940       }
2941       case IrOpcode::kCheckBigInt: {
2942         if (InputIs(node, Type::BigInt())) {
2943           VisitNoop<T>(node, truncation);
2944         } else {
2945           VisitUnop<T>(node, UseInfo::AnyTagged(),
2946                        MachineRepresentation::kTaggedPointer);
2947         }
2948         return;
2949       }
2950       case IrOpcode::kSpeculativeBigIntAsIntN:
2951       case IrOpcode::kSpeculativeBigIntAsUintN: {
2952         const bool is_asuintn =
2953             node->opcode() == IrOpcode::kSpeculativeBigIntAsUintN;
2954         const auto p = SpeculativeBigIntAsNParametersOf(node->op());
2955         DCHECK_LE(0, p.bits());
2956         DCHECK_LE(p.bits(), 64);
2957 
2958         ProcessInput<T>(node, 0,
2959                         UseInfo::CheckedBigIntTruncatingWord64(p.feedback()));
2960         SetOutput<T>(
2961             node, MachineRepresentation::kWord64,
2962             is_asuintn ? Type::UnsignedBigInt64() : Type::SignedBigInt64());
2963         if (lower<T>()) {
2964           if (p.bits() == 0) {
2965             DeferReplacement(
2966                 node, InsertTypeOverrideForVerifier(Type::UnsignedBigInt63(),
2967                                                     jsgraph_->ZeroConstant()));
2968           } else if (p.bits() == 64) {
2969             DeferReplacement(node, node->InputAt(0));
2970           } else {
2971             if (is_asuintn) {
2972               const uint64_t mask = (1ULL << p.bits()) - 1ULL;
2973               ChangeUnaryToPureBinaryOp(node, lowering->machine()->Word64And(),
2974                                         1, jsgraph_->Int64Constant(mask));
2975             } else {
2976               // We truncate the value to N bits, but to correctly interpret
2977               // negative values, we have to fill the top (64-N) bits with the
2978               // sign. This is done by shifting the value left and then back
2979               // with an arithmetic right shift. E.g. for {value} =
2980               // 0..0'0001'1101 (29n) and N = 3: {shifted} is 1010'0000'0..0
2981               // after left shift by 61 bits, {unshifted} is 1..1'1111'1101
2982               // after arithmetic right shift by 61. This is the 64 bit
2983               // representation of -3 we expect for the signed 3 bit integer
2984               // 101.
2985               const uint64_t shift = 64 - p.bits();
2986               Node* value = node->InputAt(0);
2987               Node* shifted =
2988                   graph()->NewNode(lowering->machine()->Word64Shl(), value,
2989                                    jsgraph_->Uint64Constant(shift));
2990               Node* unshifted =
2991                   graph()->NewNode(lowering->machine()->Word64Sar(), shifted,
2992                                    jsgraph_->Uint64Constant(shift));
2993 
2994               ReplaceWithPureNode(node, unshifted);
2995             }
2996           }
2997         }
2998         return;
2999       }
3000       case IrOpcode::kNumberAcos:
3001       case IrOpcode::kNumberAcosh:
3002       case IrOpcode::kNumberAsin:
3003       case IrOpcode::kNumberAsinh:
3004       case IrOpcode::kNumberAtan:
3005       case IrOpcode::kNumberAtanh:
3006       case IrOpcode::kNumberCos:
3007       case IrOpcode::kNumberCosh:
3008       case IrOpcode::kNumberExp:
3009       case IrOpcode::kNumberExpm1:
3010       case IrOpcode::kNumberLog:
3011       case IrOpcode::kNumberLog1p:
3012       case IrOpcode::kNumberLog2:
3013       case IrOpcode::kNumberLog10:
3014       case IrOpcode::kNumberCbrt:
3015       case IrOpcode::kNumberSin:
3016       case IrOpcode::kNumberSinh:
3017       case IrOpcode::kNumberTan:
3018       case IrOpcode::kNumberTanh: {
3019         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3020                      MachineRepresentation::kFloat64);
3021         if (lower<T>()) ChangeOp(node, Float64Op(node));
3022         return;
3023       }
3024       case IrOpcode::kNumberSign: {
3025         if (InputIs(node, Type::Signed32())) {
3026           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3027                        MachineRepresentation::kWord32);
3028           if (lower<T>()) DeferReplacement(node, lowering->Int32Sign(node));
3029         } else {
3030           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3031                        MachineRepresentation::kFloat64);
3032           if (lower<T>()) DeferReplacement(node, lowering->Float64Sign(node));
3033         }
3034         return;
3035       }
3036       case IrOpcode::kNumberSilenceNaN: {
3037         Type const input_type = TypeOf(node->InputAt(0));
3038         if (input_type.Is(Type::OrderedNumber())) {
3039           // No need to silence anything if the input cannot be NaN.
3040           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3041                        MachineRepresentation::kFloat64);
3042           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3043         } else {
3044           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3045                        MachineRepresentation::kFloat64);
3046           if (lower<T>()) ChangeOp(node, Float64Op(node));
3047         }
3048         return;
3049       }
3050       case IrOpcode::kNumberSqrt: {
3051         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3052                      MachineRepresentation::kFloat64);
3053         if (lower<T>()) ChangeOp(node, Float64Op(node));
3054         return;
3055       }
3056       case IrOpcode::kNumberToBoolean: {
3057         // For NumberToBoolean we don't care whether the input is 0 or
3058         // -0, since both of them are mapped to false anyways, so we
3059         // can generally pass kIdentifyZeros truncation.
3060         Type const input_type = TypeOf(node->InputAt(0));
3061         if (input_type.Is(Type::Integral32OrMinusZeroOrNaN())) {
3062           // 0, -0 and NaN all map to false, so we can safely truncate
3063           // all of them to zero here.
3064           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3065                        MachineRepresentation::kBit);
3066           if (lower<T>()) lowering->DoIntegral32ToBit(node);
3067         } else if (input_type.Is(Type::OrderedNumber())) {
3068           VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
3069                        MachineRepresentation::kBit);
3070           if (lower<T>()) lowering->DoOrderedNumberToBit(node);
3071         } else {
3072           VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
3073                        MachineRepresentation::kBit);
3074           if (lower<T>()) lowering->DoNumberToBit(node);
3075         }
3076         return;
3077       }
3078       case IrOpcode::kNumberToInt32: {
3079         // Just change representation if necessary.
3080         VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3081                      MachineRepresentation::kWord32);
3082         if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3083         return;
3084       }
3085       case IrOpcode::kNumberToString: {
3086         VisitUnop<T>(node, UseInfo::AnyTagged(),
3087                      MachineRepresentation::kTaggedPointer);
3088         return;
3089       }
3090       case IrOpcode::kNumberToUint32: {
3091         // Just change representation if necessary.
3092         VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3093                      MachineRepresentation::kWord32);
3094         if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3095         return;
3096       }
3097       case IrOpcode::kNumberToUint8Clamped: {
3098         Type const input_type = TypeOf(node->InputAt(0));
3099         if (input_type.Is(type_cache_->kUint8OrMinusZeroOrNaN)) {
3100           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3101                        MachineRepresentation::kWord32);
3102           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3103         } else if (input_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) {
3104           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3105                        MachineRepresentation::kWord32);
3106           if (lower<T>()) lowering->DoUnsigned32ToUint8Clamped(node);
3107         } else if (input_type.Is(Type::Signed32OrMinusZeroOrNaN())) {
3108           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3109                        MachineRepresentation::kWord32);
3110           if (lower<T>()) lowering->DoSigned32ToUint8Clamped(node);
3111         } else if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
3112           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3113                        MachineRepresentation::kFloat64);
3114           if (lower<T>()) lowering->DoIntegerToUint8Clamped(node);
3115         } else {
3116           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3117                        MachineRepresentation::kFloat64);
3118           if (lower<T>()) lowering->DoNumberToUint8Clamped(node);
3119         }
3120         return;
3121       }
3122       case IrOpcode::kReferenceEqual: {
3123         VisitBinop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3124         if (lower<T>()) {
3125           if (COMPRESS_POINTERS_BOOL) {
3126             ChangeOp(node, lowering->machine()->Word32Equal());
3127           } else {
3128             ChangeOp(node, lowering->machine()->WordEqual());
3129           }
3130         }
3131         return;
3132       }
3133       case IrOpcode::kSameValueNumbersOnly: {
3134         VisitBinop<T>(node, UseInfo::AnyTagged(),
3135                       MachineRepresentation::kTaggedPointer);
3136         return;
3137       }
3138       case IrOpcode::kSameValue: {
3139         if (truncation.IsUnused()) return VisitUnused<T>(node);
3140         if (BothInputsAre(node, Type::Number())) {
3141           VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
3142                         MachineRepresentation::kBit);
3143           if (lower<T>()) {
3144             ChangeOp(node, lowering->simplified()->NumberSameValue());
3145           }
3146         } else {
3147           VisitBinop<T>(node, UseInfo::AnyTagged(),
3148                         MachineRepresentation::kTaggedPointer);
3149         }
3150         return;
3151       }
3152       case IrOpcode::kTypeOf: {
3153         return VisitUnop<T>(node, UseInfo::AnyTagged(),
3154                             MachineRepresentation::kTaggedPointer);
3155       }
3156       case IrOpcode::kNewConsString: {
3157         ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());  // length
3158         ProcessInput<T>(node, 1, UseInfo::AnyTagged());         // first
3159         ProcessInput<T>(node, 2, UseInfo::AnyTagged());         // second
3160         SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3161         return;
3162       }
3163       case IrOpcode::kSpeculativeBigIntAdd: {
3164         // TODO(nicohartmann@, chromium:1073440): There should be special
3165         // handling for trunction.IsUnused() that correctly propagates deadness,
3166         // but preserves type checking which may throw exceptions. Until this
3167         // is fully supported, we lower to int64 operations but keep pushing
3168         // type constraints.
3169         if (truncation.IsUsedAsWord64()) {
3170           VisitBinop<T>(
3171               node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
3172               MachineRepresentation::kWord64);
3173           if (lower<T>()) {
3174             ChangeToPureOp(node, lowering->machine()->Int64Add());
3175           }
3176         } else {
3177           VisitBinop<T>(node,
3178                         UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
3179                         MachineRepresentation::kTaggedPointer);
3180           if (lower<T>()) {
3181             ChangeOp(node, lowering->simplified()->BigIntAdd());
3182           }
3183         }
3184         return;
3185       }
3186       case IrOpcode::kSpeculativeBigIntSubtract: {
3187         if (truncation.IsUsedAsWord64()) {
3188           VisitBinop<T>(
3189               node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
3190               MachineRepresentation::kWord64);
3191           if (lower<T>()) {
3192             ChangeToPureOp(node, lowering->machine()->Int64Sub());
3193           }
3194         } else {
3195           VisitBinop<T>(node,
3196                         UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
3197                         MachineRepresentation::kTaggedPointer);
3198           if (lower<T>()) {
3199             ChangeOp(node, lowering->simplified()->BigIntSubtract());
3200           }
3201         }
3202         return;
3203       }
3204       case IrOpcode::kSpeculativeBigIntNegate: {
3205         if (truncation.IsUsedAsWord64()) {
3206           VisitUnop<T>(node,
3207                        UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
3208                        MachineRepresentation::kWord64);
3209           if (lower<T>()) {
3210             ChangeUnaryToPureBinaryOp(node, lowering->machine()->Int64Sub(), 0,
3211                                       jsgraph_->Int64Constant(0));
3212           }
3213         } else {
3214           VisitUnop<T>(node,
3215                        UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
3216                        MachineRepresentation::kTaggedPointer);
3217           if (lower<T>()) {
3218             ChangeToPureOp(node, lowering->simplified()->BigIntNegate());
3219           }
3220         }
3221         return;
3222       }
3223       case IrOpcode::kStringConcat: {
3224         // TODO(turbofan): We currently depend on having this first length input
3225         // to make sure that the overflow check is properly scheduled before the
3226         // actual string concatenation. We should also use the length to pass it
3227         // to the builtin or decide in optimized code how to construct the
3228         // resulting string (i.e. cons string or sequential string).
3229         ProcessInput<T>(node, 0, UseInfo::TaggedSigned());  // length
3230         ProcessInput<T>(node, 1, UseInfo::AnyTagged());     // first
3231         ProcessInput<T>(node, 2, UseInfo::AnyTagged());     // second
3232         SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3233         return;
3234       }
3235       case IrOpcode::kStringEqual:
3236       case IrOpcode::kStringLessThan:
3237       case IrOpcode::kStringLessThanOrEqual: {
3238         return VisitBinop<T>(node, UseInfo::AnyTagged(),
3239                              MachineRepresentation::kTaggedPointer);
3240       }
3241       case IrOpcode::kStringCharCodeAt: {
3242         return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
3243                              MachineRepresentation::kWord32);
3244       }
3245       case IrOpcode::kStringCodePointAt: {
3246         return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
3247                              MachineRepresentation::kWord32);
3248       }
3249       case IrOpcode::kStringFromSingleCharCode: {
3250         VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3251                      MachineRepresentation::kTaggedPointer);
3252         return;
3253       }
3254       case IrOpcode::kStringFromSingleCodePoint: {
3255         VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3256                      MachineRepresentation::kTaggedPointer);
3257         return;
3258       }
3259       case IrOpcode::kStringFromCodePointAt: {
3260         return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
3261                              MachineRepresentation::kTaggedPointer);
3262       }
3263       case IrOpcode::kStringIndexOf: {
3264         ProcessInput<T>(node, 0, UseInfo::AnyTagged());
3265         ProcessInput<T>(node, 1, UseInfo::AnyTagged());
3266         ProcessInput<T>(node, 2, UseInfo::TaggedSigned());
3267         SetOutput<T>(node, MachineRepresentation::kTaggedSigned);
3268         return;
3269       }
3270       case IrOpcode::kStringLength: {
3271         // TODO(bmeurer): The input representation should be TaggedPointer.
3272         // Fix this once we have a dedicated StringConcat/JSStringAdd
3273         // operator, which marks it's output as TaggedPointer properly.
3274         VisitUnop<T>(node, UseInfo::AnyTagged(),
3275                      MachineRepresentation::kWord32);
3276         return;
3277       }
3278       case IrOpcode::kStringSubstring: {
3279         ProcessInput<T>(node, 0, UseInfo::AnyTagged());
3280         ProcessInput<T>(node, 1, UseInfo::TruncatingWord32());
3281         ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());
3282         ProcessRemainingInputs<T>(node, 3);
3283         SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3284         return;
3285       }
3286       case IrOpcode::kStringToLowerCaseIntl:
3287       case IrOpcode::kStringToUpperCaseIntl: {
3288         VisitUnop<T>(node, UseInfo::AnyTagged(),
3289                      MachineRepresentation::kTaggedPointer);
3290         return;
3291       }
3292       case IrOpcode::kCheckBounds:
3293         return VisitCheckBounds<T>(node, lowering);
3294       case IrOpcode::kCheckHeapObject: {
3295         if (InputCannotBe(node, Type::SignedSmall())) {
3296           VisitUnop<T>(node, UseInfo::AnyTagged(),
3297                        MachineRepresentation::kTaggedPointer);
3298         } else {
3299           VisitUnop<T>(
3300               node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3301               MachineRepresentation::kTaggedPointer);
3302         }
3303         if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3304         return;
3305       }
3306       case IrOpcode::kCheckIf: {
3307         ProcessInput<T>(node, 0, UseInfo::Bool());
3308         ProcessRemainingInputs<T>(node, 1);
3309         SetOutput<T>(node, MachineRepresentation::kNone);
3310         return;
3311       }
3312       case IrOpcode::kCheckInternalizedString: {
3313         VisitCheck<T>(node, Type::InternalizedString(), lowering);
3314         return;
3315       }
3316       case IrOpcode::kCheckNumber: {
3317         Type const input_type = TypeOf(node->InputAt(0));
3318         if (input_type.Is(Type::Number())) {
3319           VisitNoop<T>(node, truncation);
3320         } else {
3321           VisitUnop<T>(node, UseInfo::AnyTagged(),
3322                        MachineRepresentation::kTagged);
3323         }
3324         return;
3325       }
3326       case IrOpcode::kCheckReceiver: {
3327         VisitCheck<T>(node, Type::Receiver(), lowering);
3328         return;
3329       }
3330       case IrOpcode::kCheckReceiverOrNullOrUndefined: {
3331         VisitCheck<T>(node, Type::ReceiverOrNullOrUndefined(), lowering);
3332         return;
3333       }
3334       case IrOpcode::kCheckSmi: {
3335         const CheckParameters& params = CheckParametersOf(node->op());
3336         if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
3337           VisitUnop<T>(node,
3338                        UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros,
3339                                                            params.feedback()),
3340                        MachineRepresentation::kWord32);
3341         } else {
3342           VisitUnop<T>(
3343               node,
3344               UseInfo::CheckedSignedSmallAsTaggedSigned(params.feedback()),
3345               MachineRepresentation::kTaggedSigned);
3346         }
3347         if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3348         return;
3349       }
3350       case IrOpcode::kCheckString: {
3351         const CheckParameters& params = CheckParametersOf(node->op());
3352         if (InputIs(node, Type::String())) {
3353           VisitUnop<T>(node, UseInfo::AnyTagged(),
3354                        MachineRepresentation::kTaggedPointer);
3355           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3356         } else {
3357           VisitUnop<T>(
3358               node,
3359               UseInfo::CheckedHeapObjectAsTaggedPointer(params.feedback()),
3360               MachineRepresentation::kTaggedPointer);
3361         }
3362         return;
3363       }
3364       case IrOpcode::kCheckSymbol: {
3365         VisitCheck<T>(node, Type::Symbol(), lowering);
3366         return;
3367       }
3368 
3369       case IrOpcode::kAllocate: {
3370         ProcessInput<T>(node, 0, UseInfo::Word());
3371         ProcessRemainingInputs<T>(node, 1);
3372         SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3373         return;
3374       }
3375       case IrOpcode::kLoadFramePointer: {
3376         SetOutput<T>(node, MachineType::PointerRepresentation());
3377         return;
3378       }
3379       case IrOpcode::kLoadMessage: {
3380         if (truncation.IsUnused()) return VisitUnused<T>(node);
3381         VisitUnop<T>(node, UseInfo::Word(), MachineRepresentation::kTagged);
3382         return;
3383       }
3384       case IrOpcode::kStoreMessage: {
3385         ProcessInput<T>(node, 0, UseInfo::Word());
3386         ProcessInput<T>(node, 1, UseInfo::AnyTagged());
3387         ProcessRemainingInputs<T>(node, 2);
3388         SetOutput<T>(node, MachineRepresentation::kNone);
3389         return;
3390       }
3391       case IrOpcode::kLoadFieldByIndex: {
3392         if (truncation.IsUnused()) return VisitUnused<T>(node);
3393         VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
3394                       MachineRepresentation::kTagged);
3395         return;
3396       }
3397       case IrOpcode::kLoadField: {
3398         if (truncation.IsUnused()) return VisitUnused<T>(node);
3399         FieldAccess access = FieldAccessOf(node->op());
3400         MachineRepresentation const representation =
3401             access.machine_type.representation();
3402         VisitUnop<T>(node, UseInfoForBasePointer(access), representation);
3403         return;
3404       }
3405       case IrOpcode::kStoreField: {
3406         FieldAccess access = FieldAccessOf(node->op());
3407         Node* value_node = node->InputAt(1);
3408         NodeInfo* input_info = GetInfo(value_node);
3409         MachineRepresentation field_representation =
3410             access.machine_type.representation();
3411 
3412         // Convert to Smi if possible, such that we can avoid a write barrier.
3413         if (field_representation == MachineRepresentation::kTagged &&
3414             TypeOf(value_node).Is(Type::SignedSmall())) {
3415           field_representation = MachineRepresentation::kTaggedSigned;
3416         }
3417         WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
3418             access.base_is_tagged, field_representation, access.offset,
3419             access.type, input_info->representation(), value_node);
3420 
3421         ProcessInput<T>(node, 0, UseInfoForBasePointer(access));
3422         ProcessInput<T>(
3423             node, 1, TruncatingUseInfoFromRepresentation(field_representation));
3424         ProcessRemainingInputs<T>(node, 2);
3425         SetOutput<T>(node, MachineRepresentation::kNone);
3426         if (lower<T>()) {
3427           if (write_barrier_kind < access.write_barrier_kind) {
3428             access.write_barrier_kind = write_barrier_kind;
3429             ChangeOp(node, jsgraph_->simplified()->StoreField(access));
3430           }
3431         }
3432         return;
3433       }
3434       case IrOpcode::kLoadElement: {
3435         if (truncation.IsUnused()) return VisitUnused<T>(node);
3436         ElementAccess access = ElementAccessOf(node->op());
3437         VisitBinop<T>(node, UseInfoForBasePointer(access), UseInfo::Word(),
3438                       access.machine_type.representation());
3439         return;
3440       }
3441       case IrOpcode::kLoadStackArgument: {
3442         if (truncation.IsUnused()) return VisitUnused<T>(node);
3443         VisitBinop<T>(node, UseInfo::Word(), MachineRepresentation::kTagged);
3444         return;
3445       }
3446       case IrOpcode::kStoreElement: {
3447         ElementAccess access = ElementAccessOf(node->op());
3448         Node* value_node = node->InputAt(2);
3449         NodeInfo* input_info = GetInfo(value_node);
3450         MachineRepresentation element_representation =
3451             access.machine_type.representation();
3452 
3453         // Convert to Smi if possible, such that we can avoid a write barrier.
3454         if (element_representation == MachineRepresentation::kTagged &&
3455             TypeOf(value_node).Is(Type::SignedSmall())) {
3456           element_representation = MachineRepresentation::kTaggedSigned;
3457         }
3458         WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
3459             access.base_is_tagged, element_representation, access.type,
3460             input_info->representation(), value_node);
3461         ProcessInput<T>(node, 0, UseInfoForBasePointer(access));  // base
3462         ProcessInput<T>(node, 1, UseInfo::Word());                // index
3463         ProcessInput<T>(node, 2,
3464                         TruncatingUseInfoFromRepresentation(
3465                             element_representation));  // value
3466         ProcessRemainingInputs<T>(node, 3);
3467         SetOutput<T>(node, MachineRepresentation::kNone);
3468         if (lower<T>()) {
3469           if (write_barrier_kind < access.write_barrier_kind) {
3470             access.write_barrier_kind = write_barrier_kind;
3471             ChangeOp(node, jsgraph_->simplified()->StoreElement(access));
3472           }
3473         }
3474         return;
3475       }
3476       case IrOpcode::kNumberIsFloat64Hole: {
3477         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3478                      MachineRepresentation::kBit);
3479         return;
3480       }
3481       case IrOpcode::kTransitionAndStoreElement: {
3482         Type value_type = TypeOf(node->InputAt(2));
3483 
3484         ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // array
3485         ProcessInput<T>(node, 1, UseInfo::Word());       // index
3486 
3487         if (value_type.Is(Type::SignedSmall())) {
3488           ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());  // value
3489           if (lower<T>()) {
3490             ChangeOp(node, simplified()->StoreSignedSmallElement());
3491           }
3492         } else if (value_type.Is(Type::Number())) {
3493           ProcessInput<T>(node, 2, UseInfo::TruncatingFloat64());  // value
3494           if (lower<T>()) {
3495             Handle<Map> double_map = DoubleMapParameterOf(node->op());
3496             ChangeOp(node,
3497                      simplified()->TransitionAndStoreNumberElement(double_map));
3498           }
3499         } else if (value_type.Is(Type::NonNumber())) {
3500           ProcessInput<T>(node, 2, UseInfo::AnyTagged());  // value
3501           if (lower<T>()) {
3502             Handle<Map> fast_map = FastMapParameterOf(node->op());
3503             ChangeOp(node, simplified()->TransitionAndStoreNonNumberElement(
3504                                fast_map, value_type));
3505           }
3506         } else {
3507           ProcessInput<T>(node, 2, UseInfo::AnyTagged());  // value
3508         }
3509 
3510         ProcessRemainingInputs<T>(node, 3);
3511         SetOutput<T>(node, MachineRepresentation::kNone);
3512         return;
3513       }
3514       case IrOpcode::kLoadTypedElement: {
3515         MachineRepresentation const rep =
3516             MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3517         ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // buffer
3518         ProcessInput<T>(node, 1, UseInfo::AnyTagged());  // base pointer
3519         ProcessInput<T>(node, 2, UseInfo::Word());       // external pointer
3520         ProcessInput<T>(node, 3, UseInfo::Word());       // index
3521         ProcessRemainingInputs<T>(node, 4);
3522         SetOutput<T>(node, rep);
3523         return;
3524       }
3525       case IrOpcode::kLoadDataViewElement: {
3526         MachineRepresentation const rep =
3527             MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3528         ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // object
3529         ProcessInput<T>(node, 1, UseInfo::Word());       // base
3530         ProcessInput<T>(node, 2, UseInfo::Word());       // index
3531         ProcessInput<T>(node, 3, UseInfo::Bool());       // little-endian
3532         ProcessRemainingInputs<T>(node, 4);
3533         SetOutput<T>(node, rep);
3534         return;
3535       }
3536       case IrOpcode::kStoreTypedElement: {
3537         MachineRepresentation const rep =
3538             MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3539         ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // buffer
3540         ProcessInput<T>(node, 1, UseInfo::AnyTagged());  // base pointer
3541         ProcessInput<T>(node, 2, UseInfo::Word());       // external pointer
3542         ProcessInput<T>(node, 3, UseInfo::Word());       // index
3543         ProcessInput<T>(node, 4,
3544                         TruncatingUseInfoFromRepresentation(rep));  // value
3545         ProcessRemainingInputs<T>(node, 5);
3546         SetOutput<T>(node, MachineRepresentation::kNone);
3547         return;
3548       }
3549       case IrOpcode::kStoreDataViewElement: {
3550         MachineRepresentation const rep =
3551             MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3552         ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // object
3553         ProcessInput<T>(node, 1, UseInfo::Word());       // base
3554         ProcessInput<T>(node, 2, UseInfo::Word());       // index
3555         ProcessInput<T>(node, 3,
3556                         TruncatingUseInfoFromRepresentation(rep));  // value
3557         ProcessInput<T>(node, 4, UseInfo::Bool());  // little-endian
3558         ProcessRemainingInputs<T>(node, 5);
3559         SetOutput<T>(node, MachineRepresentation::kNone);
3560         return;
3561       }
3562       case IrOpcode::kConvertReceiver: {
3563         Type input_type = TypeOf(node->InputAt(0));
3564         VisitBinop<T>(node, UseInfo::AnyTagged(),
3565                       MachineRepresentation::kTaggedPointer);
3566         if (lower<T>()) {
3567           // Try to optimize the {node} based on the input type.
3568           if (input_type.Is(Type::Receiver())) {
3569             DeferReplacement(node, node->InputAt(0));
3570           } else if (input_type.Is(Type::NullOrUndefined())) {
3571             DeferReplacement(node, node->InputAt(1));
3572           } else if (!input_type.Maybe(Type::NullOrUndefined())) {
3573             ChangeOp(node, lowering->simplified()->ConvertReceiver(
3574                                ConvertReceiverMode::kNotNullOrUndefined));
3575           }
3576         }
3577         return;
3578       }
3579       case IrOpcode::kPlainPrimitiveToNumber: {
3580         if (InputIs(node, Type::Boolean())) {
3581           VisitUnop<T>(node, UseInfo::Bool(), MachineRepresentation::kWord32);
3582           if (lower<T>()) {
3583             ChangeToSemanticsHintForVerifier(node, node->op());
3584           }
3585         } else if (InputIs(node, Type::String())) {
3586           VisitUnop<T>(node, UseInfo::AnyTagged(),
3587                        MachineRepresentation::kTagged);
3588           if (lower<T>()) {
3589             ChangeOp(node, simplified()->StringToNumber());
3590           }
3591         } else if (truncation.IsUsedAsWord32()) {
3592           if (InputIs(node, Type::NumberOrOddball())) {
3593             VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3594                          MachineRepresentation::kWord32);
3595             if (lower<T>()) {
3596               ChangeToSemanticsHintForVerifier(node, node->op());
3597             }
3598           } else {
3599             VisitUnop<T>(node, UseInfo::AnyTagged(),
3600                          MachineRepresentation::kWord32);
3601             if (lower<T>()) {
3602               ChangeOp(node, simplified()->PlainPrimitiveToWord32());
3603             }
3604           }
3605         } else if (truncation.TruncatesOddballAndBigIntToNumber()) {
3606           if (InputIs(node, Type::NumberOrOddball())) {
3607             VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3608                          MachineRepresentation::kFloat64);
3609             if (lower<T>()) {
3610               ChangeToSemanticsHintForVerifier(node, node->op());
3611             }
3612           } else {
3613             VisitUnop<T>(node, UseInfo::AnyTagged(),
3614                          MachineRepresentation::kFloat64);
3615             if (lower<T>()) {
3616               ChangeOp(node, simplified()->PlainPrimitiveToFloat64());
3617             }
3618           }
3619         } else {
3620           VisitUnop<T>(node, UseInfo::AnyTagged(),
3621                        MachineRepresentation::kTagged);
3622         }
3623         return;
3624       }
3625       case IrOpcode::kSpeculativeToNumber: {
3626         NumberOperationParameters const& p =
3627             NumberOperationParametersOf(node->op());
3628         switch (p.hint()) {
3629           case NumberOperationHint::kSignedSmall:
3630           case NumberOperationHint::kSignedSmallInputs:
3631             VisitUnop<T>(node,
3632                          CheckedUseInfoAsWord32FromHint(
3633                              p.hint(), kDistinguishZeros, p.feedback()),
3634                          MachineRepresentation::kWord32, Type::Signed32());
3635             break;
3636           case NumberOperationHint::kNumber:
3637           case NumberOperationHint::kNumberOrBoolean:
3638           case NumberOperationHint::kNumberOrOddball:
3639             VisitUnop<T>(
3640                 node, CheckedUseInfoAsFloat64FromHint(p.hint(), p.feedback()),
3641                 MachineRepresentation::kFloat64);
3642             break;
3643         }
3644         if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3645         return;
3646       }
3647       case IrOpcode::kObjectIsArrayBufferView: {
3648         // TODO(turbofan): Introduce a Type::ArrayBufferView?
3649         VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3650         return;
3651       }
3652       case IrOpcode::kObjectIsBigInt: {
3653         VisitObjectIs<T>(node, Type::BigInt(), lowering);
3654         return;
3655       }
3656       case IrOpcode::kObjectIsCallable: {
3657         VisitObjectIs<T>(node, Type::Callable(), lowering);
3658         return;
3659       }
3660       case IrOpcode::kObjectIsConstructor: {
3661         // TODO(turbofan): Introduce a Type::Constructor?
3662         VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3663         return;
3664       }
3665       case IrOpcode::kObjectIsDetectableCallable: {
3666         VisitObjectIs<T>(node, Type::DetectableCallable(), lowering);
3667         return;
3668       }
3669       case IrOpcode::kObjectIsFiniteNumber: {
3670         Type const input_type = GetUpperBound(node->InputAt(0));
3671         if (input_type.Is(type_cache_->kSafeInteger)) {
3672           VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3673           if (lower<T>()) {
3674             DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3675           }
3676         } else if (!input_type.Maybe(Type::Number())) {
3677           VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3678           if (lower<T>()) {
3679             DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3680           }
3681         } else if (input_type.Is(Type::Number())) {
3682           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3683                        MachineRepresentation::kBit);
3684           if (lower<T>()) {
3685             ChangeOp(node, lowering->simplified()->NumberIsFinite());
3686           }
3687         } else {
3688           VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3689         }
3690         return;
3691       }
3692       case IrOpcode::kNumberIsFinite: {
3693         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3694                      MachineRepresentation::kBit);
3695         return;
3696       }
3697       case IrOpcode::kObjectIsSafeInteger: {
3698         Type const input_type = GetUpperBound(node->InputAt(0));
3699         if (input_type.Is(type_cache_->kSafeInteger)) {
3700           VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3701           if (lower<T>()) {
3702             DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3703           }
3704         } else if (!input_type.Maybe(Type::Number())) {
3705           VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3706           if (lower<T>()) {
3707             DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3708           }
3709         } else if (input_type.Is(Type::Number())) {
3710           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3711                        MachineRepresentation::kBit);
3712           if (lower<T>()) {
3713             ChangeOp(node, lowering->simplified()->NumberIsSafeInteger());
3714           }
3715         } else {
3716           VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3717         }
3718         return;
3719       }
3720       case IrOpcode::kNumberIsSafeInteger: {
3721         UNREACHABLE();
3722       }
3723       case IrOpcode::kObjectIsInteger: {
3724         Type const input_type = GetUpperBound(node->InputAt(0));
3725         if (input_type.Is(type_cache_->kSafeInteger)) {
3726           VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3727           if (lower<T>()) {
3728             DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3729           }
3730         } else if (!input_type.Maybe(Type::Number())) {
3731           VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3732           if (lower<T>()) {
3733             DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3734           }
3735         } else if (input_type.Is(Type::Number())) {
3736           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3737                        MachineRepresentation::kBit);
3738           if (lower<T>()) {
3739             ChangeOp(node, lowering->simplified()->NumberIsInteger());
3740           }
3741         } else {
3742           VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3743         }
3744         return;
3745       }
3746       case IrOpcode::kNumberIsInteger: {
3747         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3748                      MachineRepresentation::kBit);
3749         return;
3750       }
3751       case IrOpcode::kObjectIsMinusZero: {
3752         Type const input_type = GetUpperBound(node->InputAt(0));
3753         if (input_type.Is(Type::MinusZero())) {
3754           VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3755           if (lower<T>()) {
3756             DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3757           }
3758         } else if (!input_type.Maybe(Type::MinusZero())) {
3759           VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3760           if (lower<T>()) {
3761             DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3762           }
3763         } else if (input_type.Is(Type::Number())) {
3764           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3765                        MachineRepresentation::kBit);
3766           if (lower<T>()) {
3767             ChangeOp(node, simplified()->NumberIsMinusZero());
3768           }
3769         } else {
3770           VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3771         }
3772         return;
3773       }
3774       case IrOpcode::kObjectIsNaN: {
3775         Type const input_type = GetUpperBound(node->InputAt(0));
3776         if (input_type.Is(Type::NaN())) {
3777           VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3778           if (lower<T>()) {
3779             DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3780           }
3781         } else if (!input_type.Maybe(Type::NaN())) {
3782           VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3783           if (lower<T>()) {
3784             DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3785           }
3786         } else if (input_type.Is(Type::Number())) {
3787           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3788                        MachineRepresentation::kBit);
3789           if (lower<T>()) {
3790             ChangeOp(node, simplified()->NumberIsNaN());
3791           }
3792         } else {
3793           VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3794         }
3795         return;
3796       }
3797       case IrOpcode::kNumberIsNaN: {
3798         VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3799                      MachineRepresentation::kBit);
3800         return;
3801       }
3802       case IrOpcode::kObjectIsNonCallable: {
3803         VisitObjectIs<T>(node, Type::NonCallable(), lowering);
3804         return;
3805       }
3806       case IrOpcode::kObjectIsNumber: {
3807         VisitObjectIs<T>(node, Type::Number(), lowering);
3808         return;
3809       }
3810       case IrOpcode::kObjectIsReceiver: {
3811         VisitObjectIs<T>(node, Type::Receiver(), lowering);
3812         return;
3813       }
3814       case IrOpcode::kObjectIsSmi: {
3815         // TODO(turbofan): Optimize based on input representation.
3816         VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3817         return;
3818       }
3819       case IrOpcode::kObjectIsString: {
3820         VisitObjectIs<T>(node, Type::String(), lowering);
3821         return;
3822       }
3823       case IrOpcode::kObjectIsSymbol: {
3824         VisitObjectIs<T>(node, Type::Symbol(), lowering);
3825         return;
3826       }
3827       case IrOpcode::kObjectIsUndetectable: {
3828         VisitObjectIs<T>(node, Type::Undetectable(), lowering);
3829         return;
3830       }
3831       case IrOpcode::kArgumentsLength:
3832       case IrOpcode::kRestLength: {
3833         SetOutput<T>(node, MachineRepresentation::kTaggedSigned);
3834         return;
3835       }
3836       case IrOpcode::kNewDoubleElements:
3837       case IrOpcode::kNewSmiOrObjectElements: {
3838         VisitUnop<T>(node, UseInfo::Word(),
3839                      MachineRepresentation::kTaggedPointer);
3840         return;
3841       }
3842       case IrOpcode::kNewArgumentsElements: {
3843         VisitUnop<T>(node, UseInfo::TaggedSigned(),
3844                      MachineRepresentation::kTaggedPointer);
3845         return;
3846       }
3847       case IrOpcode::kCheckFloat64Hole: {
3848         Type const input_type = TypeOf(node->InputAt(0));
3849         CheckFloat64HoleMode mode =
3850             CheckFloat64HoleParametersOf(node->op()).mode();
3851         if (mode == CheckFloat64HoleMode::kAllowReturnHole) {
3852           // If {mode} is allow-return-hole _and_ the {truncation}
3853           // identifies NaN and undefined, we can just pass along
3854           // the {truncation} and completely wipe the {node}.
3855           if (truncation.IsUnused()) return VisitUnused<T>(node);
3856           if (truncation.TruncatesOddballAndBigIntToNumber()) {
3857             VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3858                          MachineRepresentation::kFloat64);
3859             if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3860             return;
3861           }
3862         }
3863         VisitUnop<T>(
3864             node, UseInfo(MachineRepresentation::kFloat64, Truncation::Any()),
3865             MachineRepresentation::kFloat64, Type::Number());
3866         if (lower<T>() && input_type.Is(Type::Number())) {
3867           DeferReplacement(node, node->InputAt(0));
3868         }
3869         return;
3870       }
3871       case IrOpcode::kCheckNotTaggedHole: {
3872         VisitUnop<T>(node, UseInfo::AnyTagged(),
3873                      MachineRepresentation::kTagged);
3874         return;
3875       }
3876       case IrOpcode::kCheckClosure: {
3877         VisitUnop<T>(
3878             node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3879             MachineRepresentation::kTaggedPointer);
3880         return;
3881       }
3882       case IrOpcode::kConvertTaggedHoleToUndefined: {
3883         if (InputIs(node, Type::NumberOrOddball()) &&
3884             truncation.IsUsedAsWord32()) {
3885           // Propagate the Word32 truncation.
3886           VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3887                        MachineRepresentation::kWord32);
3888           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3889         } else if (InputIs(node, Type::NumberOrOddball()) &&
3890                    truncation.TruncatesOddballAndBigIntToNumber()) {
3891           // Propagate the Float64 truncation.
3892           VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3893                        MachineRepresentation::kFloat64);
3894           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3895         } else if (InputIs(node, Type::NonInternal())) {
3896           VisitUnop<T>(node, UseInfo::AnyTagged(),
3897                        MachineRepresentation::kTagged);
3898           if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3899         } else {
3900           // TODO(turbofan): Add a (Tagged) truncation that identifies hole
3901           // and undefined, i.e. for a[i] === obj cases.
3902           VisitUnop<T>(node, UseInfo::AnyTagged(),
3903                        MachineRepresentation::kTagged);
3904         }
3905         return;
3906       }
3907       case IrOpcode::kCheckEqualsSymbol:
3908       case IrOpcode::kCheckEqualsInternalizedString:
3909         return VisitBinop<T>(node, UseInfo::AnyTagged(),
3910                              MachineRepresentation::kNone);
3911       case IrOpcode::kMapGuard:
3912         // Eliminate MapGuard nodes here.
3913         return VisitUnused<T>(node);
3914       case IrOpcode::kCheckMaps: {
3915         CheckMapsParameters const& p = CheckMapsParametersOf(node->op());
3916         return VisitUnop<T>(
3917             node, UseInfo::CheckedHeapObjectAsTaggedPointer(p.feedback()),
3918             MachineRepresentation::kNone);
3919       }
3920       case IrOpcode::kTransitionElementsKind: {
3921         return VisitUnop<T>(
3922             node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3923             MachineRepresentation::kNone);
3924       }
3925       case IrOpcode::kCompareMaps:
3926         return VisitUnop<T>(
3927             node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3928             MachineRepresentation::kBit);
3929       case IrOpcode::kEnsureWritableFastElements:
3930         return VisitBinop<T>(node, UseInfo::AnyTagged(),
3931                              MachineRepresentation::kTaggedPointer);
3932       case IrOpcode::kMaybeGrowFastElements: {
3933         ProcessInput<T>(node, 0, UseInfo::AnyTagged());         // object
3934         ProcessInput<T>(node, 1, UseInfo::AnyTagged());         // elements
3935         ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());  // index
3936         ProcessInput<T>(node, 3, UseInfo::TruncatingWord32());  // length
3937         ProcessRemainingInputs<T>(node, 4);
3938         SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3939         return;
3940       }
3941 
3942       case IrOpcode::kDateNow:
3943         VisitInputs<T>(node);
3944         return SetOutput<T>(node, MachineRepresentation::kTagged);
3945       case IrOpcode::kFrameState:
3946         return VisitFrameState<T>(FrameState{node});
3947       case IrOpcode::kStateValues:
3948         return VisitStateValues<T>(node);
3949       case IrOpcode::kObjectState:
3950         return VisitObjectState<T>(node);
3951       case IrOpcode::kObjectId:
3952         return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3953 
3954       case IrOpcode::kTypeGuard: {
3955         if (truncation.IsUnused()) return VisitUnused<T>(node);
3956 
3957         // We just get rid of the sigma here, choosing the best representation
3958         // for the sigma's type.
3959         Type type = TypeOf(node);
3960         MachineRepresentation representation =
3961             GetOutputInfoForPhi(node, type, truncation);
3962 
3963         // Here we pretend that the input has the sigma's type for the
3964         // conversion.
3965         UseInfo use(representation, truncation);
3966         if (propagate<T>()) {
3967           EnqueueInput<T>(node, 0, use);
3968         } else if (lower<T>()) {
3969           ConvertInput(node, 0, use, type);
3970         }
3971         ProcessRemainingInputs<T>(node, 1);
3972         SetOutput<T>(node, representation);
3973         return;
3974       }
3975 
3976       case IrOpcode::kFoldConstant:
3977         VisitInputs<T>(node);
3978         return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3979 
3980       case IrOpcode::kFinishRegion:
3981         VisitInputs<T>(node);
3982         // Assume the output is tagged pointer.
3983         return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3984 
3985       case IrOpcode::kReturn:
3986         VisitReturn<T>(node);
3987         // Assume the output is tagged.
3988         return SetOutput<T>(node, MachineRepresentation::kTagged);
3989 
3990       case IrOpcode::kFindOrderedHashMapEntry: {
3991         Type const key_type = TypeOf(node->InputAt(1));
3992         if (key_type.Is(Type::Signed32OrMinusZero())) {
3993           VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
3994                         MachineType::PointerRepresentation());
3995           if (lower<T>()) {
3996             ChangeOp(
3997                 node,
3998                 lowering->simplified()->FindOrderedHashMapEntryForInt32Key());
3999           }
4000         } else {
4001           VisitBinop<T>(node, UseInfo::AnyTagged(),
4002                         MachineRepresentation::kTaggedSigned);
4003         }
4004         return;
4005       }
4006 
4007       case IrOpcode::kFastApiCall: {
4008         VisitFastApiCall<T>(node, lowering);
4009         return;
4010       }
4011 
4012       // Operators with all inputs tagged and no or tagged output have uniform
4013       // handling.
4014       case IrOpcode::kEnd:
4015       case IrOpcode::kIfSuccess:
4016       case IrOpcode::kIfException:
4017       case IrOpcode::kIfTrue:
4018       case IrOpcode::kIfFalse:
4019       case IrOpcode::kIfValue:
4020       case IrOpcode::kIfDefault:
4021       case IrOpcode::kDeoptimize:
4022       case IrOpcode::kEffectPhi:
4023       case IrOpcode::kTerminate:
4024       case IrOpcode::kCheckpoint:
4025       case IrOpcode::kLoop:
4026       case IrOpcode::kMerge:
4027       case IrOpcode::kThrow:
4028       case IrOpcode::kBeginRegion:
4029       case IrOpcode::kProjection:
4030       case IrOpcode::kOsrValue:
4031       case IrOpcode::kArgumentsElementsState:
4032       case IrOpcode::kArgumentsLengthState:
4033       case IrOpcode::kUnreachable:
4034       case IrOpcode::kRuntimeAbort:
4035 // All JavaScript operators except JSToNumber, JSToNumberConvertBigInt,
4036 // kJSToNumeric and JSWasmCall have uniform handling.
4037 #define OPCODE_CASE(name, ...) case IrOpcode::k##name:
4038         JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
4039         JS_OBJECT_OP_LIST(OPCODE_CASE)
4040         JS_CONTEXT_OP_LIST(OPCODE_CASE)
4041         JS_OTHER_OP_LIST(OPCODE_CASE)
4042 #undef OPCODE_CASE
4043       case IrOpcode::kJSBitwiseNot:
4044       case IrOpcode::kJSDecrement:
4045       case IrOpcode::kJSIncrement:
4046       case IrOpcode::kJSNegate:
4047       case IrOpcode::kJSToLength:
4048       case IrOpcode::kJSToName:
4049       case IrOpcode::kJSToObject:
4050       case IrOpcode::kJSToString:
4051       case IrOpcode::kJSParseInt:
4052 #if V8_ENABLE_WEBASSEMBLY
4053         if (node->opcode() == IrOpcode::kJSWasmCall) {
4054           return VisitJSWasmCall<T>(node, lowering);
4055         }
4056 #endif  // V8_ENABLE_WEBASSEMBLY
4057         VisitInputs<T>(node);
4058         // Assume the output is tagged.
4059         return SetOutput<T>(node, MachineRepresentation::kTagged);
4060       case IrOpcode::kDeadValue:
4061         ProcessInput<T>(node, 0, UseInfo::Any());
4062         return SetOutput<T>(node, MachineRepresentation::kNone);
4063       case IrOpcode::kStaticAssert:
4064         DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
4065         return VisitUnop<T>(node, UseInfo::Bool(),
4066                             MachineRepresentation::kTagged);
4067       case IrOpcode::kAssertType:
4068         return VisitUnop<T>(node, UseInfo::AnyTagged(),
4069                             MachineRepresentation::kTagged);
4070       case IrOpcode::kVerifyType: {
4071         Type inputType = TypeOf(node->InputAt(0));
4072         VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged,
4073                      inputType);
4074         if (lower<T>()) {
4075           if (inputType.CanBeAsserted()) {
4076             ChangeOp(node, simplified()->AssertType(inputType));
4077           } else {
4078             if (!FLAG_fuzzing) {
4079 #ifdef DEBUG
4080               inputType.Print();
4081 #endif
4082               FATAL("%%VerifyType: unsupported type");
4083             }
4084             DeferReplacement(node, node->InputAt(0));
4085           }
4086         }
4087         return;
4088       }
4089 
4090       default:
4091         FATAL(
4092             "Representation inference: unsupported opcode %i (%s), node #%i\n.",
4093             node->opcode(), node->op()->mnemonic(), node->id());
4094         break;
4095     }
4096     UNREACHABLE();
4097   }
4098 
DisconnectFromEffectAndControl(Node * node)4099   void DisconnectFromEffectAndControl(Node* node) {
4100     if (node->op()->EffectInputCount() == 1) {
4101       Node* control = NodeProperties::GetControlInput(node);
4102       Node* effect = NodeProperties::GetEffectInput(node);
4103       ReplaceEffectControlUses(node, effect, control);
4104     } else {
4105       DCHECK_EQ(0, node->op()->EffectInputCount());
4106       DCHECK_EQ(0, node->op()->ControlOutputCount());
4107       DCHECK_EQ(0, node->op()->EffectOutputCount());
4108     }
4109   }
4110 
DeferReplacement(Node * node,Node * replacement)4111   void DeferReplacement(Node* node, Node* replacement) {
4112     TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
4113           node->op()->mnemonic(), replacement->id(),
4114           replacement->op()->mnemonic());
4115 
4116     DisconnectFromEffectAndControl(node);
4117     node->NullAllInputs();  // Node is now dead.
4118 
4119     replacements_.push_back(node);
4120     replacements_.push_back(replacement);
4121 
4122     NotifyNodeReplaced(node, replacement);
4123   }
4124 
InsertTypeOverrideForVerifier(const Type & type,Node * node)4125   Node* InsertTypeOverrideForVerifier(const Type& type, Node* node) {
4126     if (verification_enabled()) {
4127       DCHECK(!type.IsInvalid());
4128       node = graph()->NewNode(common()->SLVerifierHint(nullptr, type), node);
4129       verifier_->RecordHint(node);
4130     }
4131     return node;
4132   }
4133 
ChangeToSemanticsHintForVerifier(Node * node,const Operator * semantics)4134   void ChangeToSemanticsHintForVerifier(Node* node, const Operator* semantics) {
4135     DCHECK_EQ(node->op()->ValueInputCount(), 1);
4136     DCHECK_EQ(node->op()->EffectInputCount(), 0);
4137     DCHECK_EQ(node->op()->ControlInputCount(), 0);
4138     if (verification_enabled()) {
4139       ChangeOp(node, common()->SLVerifierHint(semantics, base::nullopt));
4140       verifier_->RecordHint(node);
4141     } else {
4142       DeferReplacement(node, node->InputAt(0));
4143     }
4144   }
4145 
4146  private:
ChangeOp(Node * node,const Operator * new_op)4147   void ChangeOp(Node* node, const Operator* new_op) {
4148     compiler::NodeProperties::ChangeOp(node, new_op);
4149 
4150     if (V8_UNLIKELY(observe_node_manager_ != nullptr))
4151       observe_node_manager_->OnNodeChanged(kSimplifiedLoweringReducerName, node,
4152                                            node);
4153   }
4154 
NotifyNodeReplaced(Node * node,Node * replacement)4155   void NotifyNodeReplaced(Node* node, Node* replacement) {
4156     if (V8_UNLIKELY(observe_node_manager_ != nullptr))
4157       observe_node_manager_->OnNodeChanged(kSimplifiedLoweringReducerName, node,
4158                                            replacement);
4159   }
4160 
4161   JSGraph* jsgraph_;
4162   JSHeapBroker* broker_;
4163   Zone* zone_;                      // Temporary zone.
4164   // Map from node to its uses that might need to be revisited.
4165   ZoneMap<Node*, ZoneVector<Node*>> might_need_revisit_;
4166   size_t count_;                    // number of nodes in the graph
4167   ZoneVector<NodeInfo> info_;       // node id -> usage information
4168 #ifdef DEBUG
4169   ZoneVector<InputUseInfos> node_input_use_infos_;  // Debug information about
4170                                                     // requirements on inputs.
4171 #endif                                              // DEBUG
4172   NodeVector replacements_;         // replacements to be done after lowering
4173   RepresentationChanger* changer_;  // for inserting representation changes
4174   ZoneQueue<Node*> revisit_queue_;  // Queue for revisiting nodes.
4175 
4176   struct NodeState {
4177     Node* node;
4178     int input_index;
4179   };
4180   NodeVector traversal_nodes_;  // Order in which to traverse the nodes.
4181   // TODO(danno): RepresentationSelector shouldn't know anything about the
4182   // source positions table, but must for now since there currently is no other
4183   // way to pass down source position information to nodes created during
4184   // lowering. Once this phase becomes a vanilla reducer, it should get source
4185   // position information via the SourcePositionWrapper like all other reducers.
4186   SourcePositionTable* source_positions_;
4187   NodeOriginTable* node_origins_;
4188   TypeCache const* type_cache_;
4189   OperationTyper op_typer_;  // helper for the feedback typer
4190   TickCounter* const tick_counter_;
4191   Linkage* const linkage_;
4192   ObserveNodeManager* const observe_node_manager_;
4193   SimplifiedLoweringVerifier* verifier_;  // Used to verify output graph.
4194 
GetInfo(Node * node)4195   NodeInfo* GetInfo(Node* node) {
4196     DCHECK(node->id() < count_);
4197     return &info_[node->id()];
4198   }
zone()4199   Zone* zone() { return zone_; }
graph_zone()4200   Zone* graph_zone() { return jsgraph_->zone(); }
linkage()4201   Linkage* linkage() { return linkage_; }
4202 };
4203 
4204 // Template specializations
4205 
4206 // Enqueue {use_node}'s {index} input if the {use_info} contains new information
4207 // for that input node.
4208 template <>
EnqueueInput(Node * use_node,int index,UseInfo use_info)4209 void RepresentationSelector::EnqueueInput<PROPAGATE>(Node* use_node, int index,
4210                                                      UseInfo use_info) {
4211   Node* node = use_node->InputAt(index);
4212   NodeInfo* info = GetInfo(node);
4213 #ifdef DEBUG
4214   // Check monotonicity of input requirements.
4215   node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
4216                                                          use_info);
4217 #endif  // DEBUG
4218   if (info->unvisited()) {
4219     info->AddUse(use_info);
4220     TRACE("  initial #%i: %s\n", node->id(), info->truncation().description());
4221     return;
4222   }
4223   TRACE("   queue #%i?: %s\n", node->id(), info->truncation().description());
4224   if (info->AddUse(use_info)) {
4225     // New usage information for the node is available.
4226     if (!info->queued()) {
4227       DCHECK(info->visited());
4228       revisit_queue_.push(node);
4229       info->set_queued();
4230       TRACE("   added: %s\n", info->truncation().description());
4231     } else {
4232       TRACE(" inqueue: %s\n", info->truncation().description());
4233     }
4234   }
4235 }
4236 
4237 template <>
SetOutput(Node * node,MachineRepresentation representation,Type restriction_type)4238 void RepresentationSelector::SetOutput<PROPAGATE>(
4239     Node* node, MachineRepresentation representation, Type restriction_type) {
4240   NodeInfo* const info = GetInfo(node);
4241   info->set_restriction_type(restriction_type);
4242 }
4243 
4244 template <>
SetOutput(Node * node,MachineRepresentation representation,Type restriction_type)4245 void RepresentationSelector::SetOutput<RETYPE>(
4246     Node* node, MachineRepresentation representation, Type restriction_type) {
4247   NodeInfo* const info = GetInfo(node);
4248   DCHECK(restriction_type.Is(info->restriction_type()));
4249   info->set_output(representation);
4250 }
4251 
4252 template <>
SetOutput(Node * node,MachineRepresentation representation,Type restriction_type)4253 void RepresentationSelector::SetOutput<LOWER>(
4254     Node* node, MachineRepresentation representation, Type restriction_type) {
4255   NodeInfo* const info = GetInfo(node);
4256   DCHECK_EQ(info->representation(), representation);
4257   DCHECK(restriction_type.Is(info->restriction_type()));
4258   USE(info);
4259 }
4260 
4261 template <>
ProcessInput(Node * node,int index,UseInfo use)4262 void RepresentationSelector::ProcessInput<PROPAGATE>(Node* node, int index,
4263                                                      UseInfo use) {
4264   DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
4265                  !node->op()->HasProperty(Operator::kNoDeopt) &&
4266                      node->op()->EffectInputCount() > 0);
4267   EnqueueInput<PROPAGATE>(node, index, use);
4268 }
4269 
4270 template <>
ProcessInput(Node * node,int index,UseInfo use)4271 void RepresentationSelector::ProcessInput<RETYPE>(Node* node, int index,
4272                                                   UseInfo use) {
4273   DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
4274                  !node->op()->HasProperty(Operator::kNoDeopt) &&
4275                      node->op()->EffectInputCount() > 0);
4276 }
4277 
4278 template <>
ProcessInput(Node * node,int index,UseInfo use)4279 void RepresentationSelector::ProcessInput<LOWER>(Node* node, int index,
4280                                                  UseInfo use) {
4281   DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
4282                  !node->op()->HasProperty(Operator::kNoDeopt) &&
4283                      node->op()->EffectInputCount() > 0);
4284   ConvertInput(node, index, use);
4285 }
4286 
4287 template <>
ProcessRemainingInputs(Node * node,int index)4288 void RepresentationSelector::ProcessRemainingInputs<PROPAGATE>(Node* node,
4289                                                                int index) {
4290   DCHECK_GE(index, NodeProperties::PastContextIndex(node));
4291 
4292   // Enqueue other inputs (effects, control).
4293   for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
4294        i < node->InputCount(); ++i) {
4295     EnqueueInput<PROPAGATE>(node, i);
4296   }
4297 }
4298 
4299 // The default, most general visitation case. For {node}, process all value,
4300 // context, frame state, effect, and control inputs, assuming that value
4301 // inputs should have {kRepTagged} representation and can observe all output
4302 // values {kTypeAny}.
4303 template <>
VisitInputs(Node * node)4304 void RepresentationSelector::VisitInputs<PROPAGATE>(Node* node) {
4305   int first_effect_index = NodeProperties::FirstEffectIndex(node);
4306   // Visit value, context and frame state inputs as tagged.
4307   for (int i = 0; i < first_effect_index; i++) {
4308     ProcessInput<PROPAGATE>(node, i, UseInfo::AnyTagged());
4309   }
4310   // Only enqueue other inputs (effects, control).
4311   for (int i = first_effect_index; i < node->InputCount(); i++) {
4312     EnqueueInput<PROPAGATE>(node, i);
4313   }
4314 }
4315 
4316 template <>
VisitInputs(Node * node)4317 void RepresentationSelector::VisitInputs<LOWER>(Node* node) {
4318   int first_effect_index = NodeProperties::FirstEffectIndex(node);
4319   // Visit value, context and frame state inputs as tagged.
4320   for (int i = 0; i < first_effect_index; i++) {
4321     ProcessInput<LOWER>(node, i, UseInfo::AnyTagged());
4322   }
4323 }
4324 
4325 template <>
InsertUnreachableIfNecessary(Node * node)4326 void RepresentationSelector::InsertUnreachableIfNecessary<LOWER>(Node* node) {
4327   // If the node is effectful and it produces an impossible value, then we
4328   // insert Unreachable node after it.
4329   if (node->op()->ValueOutputCount() > 0 &&
4330       node->op()->EffectOutputCount() > 0 &&
4331       node->opcode() != IrOpcode::kUnreachable && TypeOf(node).IsNone()) {
4332     Node* control = (node->op()->ControlOutputCount() == 0)
4333                         ? NodeProperties::GetControlInput(node, 0)
4334                         : NodeProperties::FindSuccessfulControlProjection(node);
4335 
4336     Node* unreachable =
4337         graph()->NewNode(common()->Unreachable(), node, control);
4338 
4339     // Insert unreachable node and replace all the effect uses of the {node}
4340     // with the new unreachable node.
4341     for (Edge edge : node->use_edges()) {
4342       if (!NodeProperties::IsEffectEdge(edge)) continue;
4343       // Make sure to not overwrite the unreachable node's input. That would
4344       // create a cycle.
4345       if (edge.from() == unreachable) continue;
4346       // Avoid messing up the exceptional path.
4347       if (edge.from()->opcode() == IrOpcode::kIfException) {
4348         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
4349         DCHECK_EQ(NodeProperties::GetControlInput(edge.from()), node);
4350         continue;
4351       }
4352 
4353       edge.UpdateTo(unreachable);
4354     }
4355   }
4356 }
4357 
SimplifiedLowering(JSGraph * jsgraph,JSHeapBroker * broker,Zone * zone,SourcePositionTable * source_positions,NodeOriginTable * node_origins,TickCounter * tick_counter,Linkage * linkage,OptimizedCompilationInfo * info,ObserveNodeManager * observe_node_manager)4358 SimplifiedLowering::SimplifiedLowering(
4359     JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
4360     SourcePositionTable* source_positions, NodeOriginTable* node_origins,
4361     TickCounter* tick_counter, Linkage* linkage, OptimizedCompilationInfo* info,
4362     ObserveNodeManager* observe_node_manager)
4363     : jsgraph_(jsgraph),
4364       broker_(broker),
4365       zone_(zone),
4366       type_cache_(TypeCache::Get()),
4367       source_positions_(source_positions),
4368       node_origins_(node_origins),
4369       tick_counter_(tick_counter),
4370       linkage_(linkage),
4371       info_(info),
4372       observe_node_manager_(observe_node_manager) {}
4373 
LowerAllNodes()4374 void SimplifiedLowering::LowerAllNodes() {
4375   SimplifiedLoweringVerifier* verifier = nullptr;
4376   if (FLAG_verify_simplified_lowering) {
4377     verifier = zone_->New<SimplifiedLoweringVerifier>(zone_, graph());
4378   }
4379   RepresentationChanger changer(jsgraph(), broker_, verifier);
4380   RepresentationSelector selector(
4381       jsgraph(), broker_, zone_, &changer, source_positions_, node_origins_,
4382       tick_counter_, linkage_, observe_node_manager_, verifier);
4383   selector.Run(this);
4384 }
4385 
DoJSToNumberOrNumericTruncatesToFloat64(Node * node,RepresentationSelector * selector)4386 void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
4387     Node* node, RepresentationSelector* selector) {
4388   DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
4389          node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
4390          node->opcode() == IrOpcode::kJSToNumeric);
4391   Node* value = node->InputAt(0);
4392   Node* context = node->InputAt(1);
4393   Node* frame_state = node->InputAt(2);
4394   Node* effect = node->InputAt(3);
4395   Node* control = node->InputAt(4);
4396 
4397   Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
4398   Node* branch0 =
4399       graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
4400 
4401   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4402   Node* etrue0 = effect;
4403   Node* vtrue0;
4404   {
4405     vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
4406     vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
4407   }
4408 
4409   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4410   Node* efalse0 = effect;
4411   Node* vfalse0;
4412   {
4413     Operator const* op =
4414         node->opcode() == IrOpcode::kJSToNumber
4415             ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4416                    ? ToNumberConvertBigIntOperator()
4417                    : ToNumberOperator())
4418             : ToNumericOperator();
4419     Node* code = node->opcode() == IrOpcode::kJSToNumber
4420                      ? ToNumberCode()
4421                      : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4422                             ? ToNumberConvertBigIntCode()
4423                             : ToNumericCode());
4424     vfalse0 = efalse0 = if_false0 = graph()->NewNode(
4425         op, code, value, context, frame_state, efalse0, if_false0);
4426 
4427     // Update potential {IfException} uses of {node} to point to the above
4428     // stub call node instead.
4429     Node* on_exception = nullptr;
4430     if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
4431       NodeProperties::ReplaceControlInput(on_exception, vfalse0);
4432       NodeProperties::ReplaceEffectInput(on_exception, efalse0);
4433       if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
4434     }
4435 
4436     Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
4437     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4438 
4439     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4440     Node* etrue1 = efalse0;
4441     Node* vtrue1;
4442     {
4443       vtrue1 =
4444           graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
4445       vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
4446     }
4447 
4448     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4449     Node* efalse1 = efalse0;
4450     Node* vfalse1;
4451     {
4452       vfalse1 = efalse1 = graph()->NewNode(
4453           simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
4454           efalse1, if_false1);
4455     }
4456 
4457     if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
4458     efalse0 =
4459         graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
4460     vfalse0 =
4461         graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
4462                          vtrue1, vfalse1, if_false0);
4463   }
4464 
4465   control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
4466   effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
4467   value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
4468                            vtrue0, vfalse0, control);
4469 
4470   // Replace effect and control uses appropriately.
4471   for (Edge edge : node->use_edges()) {
4472     if (NodeProperties::IsControlEdge(edge)) {
4473       if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
4474         edge.from()->ReplaceUses(control);
4475         edge.from()->Kill();
4476       } else {
4477         DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
4478         edge.UpdateTo(control);
4479       }
4480     } else if (NodeProperties::IsEffectEdge(edge)) {
4481       edge.UpdateTo(effect);
4482     }
4483   }
4484 
4485   selector->DeferReplacement(node, value);
4486 }
4487 
DoJSToNumberOrNumericTruncatesToWord32(Node * node,RepresentationSelector * selector)4488 void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
4489     Node* node, RepresentationSelector* selector) {
4490   DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
4491          node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
4492          node->opcode() == IrOpcode::kJSToNumeric);
4493   Node* value = node->InputAt(0);
4494   Node* context = node->InputAt(1);
4495   Node* frame_state = node->InputAt(2);
4496   Node* effect = node->InputAt(3);
4497   Node* control = node->InputAt(4);
4498 
4499   Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
4500   Node* branch0 =
4501       graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
4502 
4503   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4504   Node* etrue0 = effect;
4505   Node* vtrue0 =
4506       graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
4507 
4508   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4509   Node* efalse0 = effect;
4510   Node* vfalse0;
4511   {
4512     Operator const* op =
4513         node->opcode() == IrOpcode::kJSToNumber
4514             ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4515                    ? ToNumberConvertBigIntOperator()
4516                    : ToNumberOperator())
4517             : ToNumericOperator();
4518     Node* code = node->opcode() == IrOpcode::kJSToNumber
4519                      ? ToNumberCode()
4520                      : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4521                             ? ToNumberConvertBigIntCode()
4522                             : ToNumericCode());
4523     vfalse0 = efalse0 = if_false0 = graph()->NewNode(
4524         op, code, value, context, frame_state, efalse0, if_false0);
4525 
4526     // Update potential {IfException} uses of {node} to point to the above
4527     // stub call node instead.
4528     Node* on_exception = nullptr;
4529     if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
4530       NodeProperties::ReplaceControlInput(on_exception, vfalse0);
4531       NodeProperties::ReplaceEffectInput(on_exception, efalse0);
4532       if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
4533     }
4534 
4535     Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
4536     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4537 
4538     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4539     Node* etrue1 = efalse0;
4540     Node* vtrue1 =
4541         graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
4542 
4543     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4544     Node* efalse1 = efalse0;
4545     Node* vfalse1;
4546     {
4547       vfalse1 = efalse1 = graph()->NewNode(
4548           simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
4549           efalse1, if_false1);
4550       vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
4551     }
4552 
4553     if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
4554     efalse0 =
4555         graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
4556     vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
4557                                vtrue1, vfalse1, if_false0);
4558   }
4559 
4560   control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
4561   effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
4562   value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
4563                            vtrue0, vfalse0, control);
4564 
4565   // Replace effect and control uses appropriately.
4566   for (Edge edge : node->use_edges()) {
4567     if (NodeProperties::IsControlEdge(edge)) {
4568       if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
4569         edge.from()->ReplaceUses(control);
4570         edge.from()->Kill();
4571       } else {
4572         DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
4573         edge.UpdateTo(control);
4574       }
4575     } else if (NodeProperties::IsEffectEdge(edge)) {
4576       edge.UpdateTo(effect);
4577     }
4578   }
4579 
4580   selector->DeferReplacement(node, value);
4581 }
4582 
Float64Round(Node * const node)4583 Node* SimplifiedLowering::Float64Round(Node* const node) {
4584   Node* const one = jsgraph()->Float64Constant(1.0);
4585   Node* const one_half = jsgraph()->Float64Constant(0.5);
4586   Node* const input = node->InputAt(0);
4587 
4588   // Round up towards Infinity, and adjust if the difference exceeds 0.5.
4589   Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
4590                                   node->InputAt(0));
4591   return graph()->NewNode(
4592       common()->Select(MachineRepresentation::kFloat64),
4593       graph()->NewNode(
4594           machine()->Float64LessThanOrEqual(),
4595           graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
4596       result, graph()->NewNode(machine()->Float64Sub(), result, one));
4597 }
4598 
Float64Sign(Node * const node)4599 Node* SimplifiedLowering::Float64Sign(Node* const node) {
4600   Node* const minus_one = jsgraph()->Float64Constant(-1.0);
4601   Node* const zero = jsgraph()->Float64Constant(0.0);
4602   Node* const one = jsgraph()->Float64Constant(1.0);
4603 
4604   Node* const input = node->InputAt(0);
4605 
4606   return graph()->NewNode(
4607       common()->Select(MachineRepresentation::kFloat64),
4608       graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
4609       graph()->NewNode(
4610           common()->Select(MachineRepresentation::kFloat64),
4611           graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
4612           input));
4613 }
4614 
Int32Abs(Node * const node)4615 Node* SimplifiedLowering::Int32Abs(Node* const node) {
4616   Node* const input = node->InputAt(0);
4617 
4618   // Generate case for absolute integer value.
4619   //
4620   //    let sign = input >> 31 in
4621   //    (input ^ sign) - sign
4622 
4623   Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
4624                                 jsgraph()->Int32Constant(31));
4625   return graph()->NewNode(machine()->Int32Sub(),
4626                           graph()->NewNode(machine()->Word32Xor(), input, sign),
4627                           sign);
4628 }
4629 
Int32Div(Node * const node)4630 Node* SimplifiedLowering::Int32Div(Node* const node) {
4631   Int32BinopMatcher m(node);
4632   Node* const zero = jsgraph()->Int32Constant(0);
4633   Node* const minus_one = jsgraph()->Int32Constant(-1);
4634   Node* const lhs = m.left().node();
4635   Node* const rhs = m.right().node();
4636 
4637   if (m.right().Is(-1)) {
4638     return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
4639   } else if (m.right().Is(0)) {
4640     return rhs;
4641   } else if (machine()->Int32DivIsSafe() || m.right().HasResolvedValue()) {
4642     return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
4643   }
4644 
4645   // General case for signed integer division.
4646   //
4647   //    if 0 < rhs then
4648   //      lhs / rhs
4649   //    else
4650   //      if rhs < -1 then
4651   //        lhs / rhs
4652   //      else if rhs == 0 then
4653   //        0
4654   //      else
4655   //        0 - lhs
4656   //
4657   // Note: We do not use the Diamond helper class here, because it really hurts
4658   // readability with nested diamonds.
4659   const Operator* const merge_op = common()->Merge(2);
4660   const Operator* const phi_op =
4661       common()->Phi(MachineRepresentation::kWord32, 2);
4662 
4663   Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
4664   Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
4665                                    graph()->start());
4666 
4667   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4668   Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
4669 
4670   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4671   Node* false0;
4672   {
4673     Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
4674     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4675 
4676     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4677     Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
4678 
4679     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4680     Node* false1;
4681     {
4682       Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4683       Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
4684 
4685       Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
4686       Node* true2 = zero;
4687 
4688       Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
4689       Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
4690 
4691       if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
4692       false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
4693     }
4694 
4695     if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4696     false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4697   }
4698 
4699   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4700   return graph()->NewNode(phi_op, true0, false0, merge0);
4701 }
4702 
Int32Mod(Node * const node)4703 Node* SimplifiedLowering::Int32Mod(Node* const node) {
4704   Int32BinopMatcher m(node);
4705   Node* const zero = jsgraph()->Int32Constant(0);
4706   Node* const minus_one = jsgraph()->Int32Constant(-1);
4707   Node* const lhs = m.left().node();
4708   Node* const rhs = m.right().node();
4709 
4710   if (m.right().Is(-1) || m.right().Is(0)) {
4711     return zero;
4712   } else if (m.right().HasResolvedValue()) {
4713     return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
4714   }
4715 
4716   // General case for signed integer modulus, with optimization for (unknown)
4717   // power of 2 right hand side.
4718   //
4719   //   if 0 < rhs then
4720   //     msk = rhs - 1
4721   //     if rhs & msk != 0 then
4722   //       lhs % rhs
4723   //     else
4724   //       if lhs < 0 then
4725   //         -(-lhs & msk)
4726   //       else
4727   //         lhs & msk
4728   //   else
4729   //     if rhs < -1 then
4730   //       lhs % rhs
4731   //     else
4732   //       zero
4733   //
4734   // Note: We do not use the Diamond helper class here, because it really hurts
4735   // readability with nested diamonds.
4736   const Operator* const merge_op = common()->Merge(2);
4737   const Operator* const phi_op =
4738       common()->Phi(MachineRepresentation::kWord32, 2);
4739 
4740   Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
4741   Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
4742                                    graph()->start());
4743 
4744   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4745   Node* true0;
4746   {
4747     Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
4748 
4749     Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
4750     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
4751 
4752     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4753     Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
4754 
4755     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4756     Node* false1;
4757     {
4758       Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
4759       Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
4760                                        check2, if_false1);
4761 
4762       Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
4763       Node* true2 = graph()->NewNode(
4764           machine()->Int32Sub(), zero,
4765           graph()->NewNode(machine()->Word32And(),
4766                            graph()->NewNode(machine()->Int32Sub(), zero, lhs),
4767                            msk));
4768 
4769       Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
4770       Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
4771 
4772       if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
4773       false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
4774     }
4775 
4776     if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
4777     true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
4778   }
4779 
4780   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4781   Node* false0;
4782   {
4783     Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
4784     Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
4785                                      check1, if_false0);
4786 
4787     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4788     Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
4789 
4790     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4791     Node* false1 = zero;
4792 
4793     if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4794     false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4795   }
4796 
4797   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4798   return graph()->NewNode(phi_op, true0, false0, merge0);
4799 }
4800 
Int32Sign(Node * const node)4801 Node* SimplifiedLowering::Int32Sign(Node* const node) {
4802   Node* const minus_one = jsgraph()->Int32Constant(-1);
4803   Node* const zero = jsgraph()->Int32Constant(0);
4804   Node* const one = jsgraph()->Int32Constant(1);
4805 
4806   Node* const input = node->InputAt(0);
4807 
4808   return graph()->NewNode(
4809       common()->Select(MachineRepresentation::kWord32),
4810       graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
4811       graph()->NewNode(
4812           common()->Select(MachineRepresentation::kWord32),
4813           graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
4814           zero));
4815 }
4816 
Uint32Div(Node * const node)4817 Node* SimplifiedLowering::Uint32Div(Node* const node) {
4818   Uint32BinopMatcher m(node);
4819   Node* const zero = jsgraph()->Uint32Constant(0);
4820   Node* const lhs = m.left().node();
4821   Node* const rhs = m.right().node();
4822 
4823   if (m.right().Is(0)) {
4824     return zero;
4825   } else if (machine()->Uint32DivIsSafe() || m.right().HasResolvedValue()) {
4826     return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
4827   }
4828 
4829   Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4830   Diamond d(graph(), common(), check, BranchHint::kFalse);
4831   Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
4832   return d.Phi(MachineRepresentation::kWord32, zero, div);
4833 }
4834 
Uint32Mod(Node * const node)4835 Node* SimplifiedLowering::Uint32Mod(Node* const node) {
4836   Uint32BinopMatcher m(node);
4837   Node* const minus_one = jsgraph()->Int32Constant(-1);
4838   Node* const zero = jsgraph()->Uint32Constant(0);
4839   Node* const lhs = m.left().node();
4840   Node* const rhs = m.right().node();
4841 
4842   if (m.right().Is(0)) {
4843     return zero;
4844   } else if (m.right().HasResolvedValue()) {
4845     return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
4846   }
4847 
4848   // General case for unsigned integer modulus, with optimization for (unknown)
4849   // power of 2 right hand side.
4850   //
4851   //   if rhs == 0 then
4852   //     zero
4853   //   else
4854   //     msk = rhs - 1
4855   //     if rhs & msk != 0 then
4856   //       lhs % rhs
4857   //     else
4858   //       lhs & msk
4859   //
4860   // Note: We do not use the Diamond helper class here, because it really hurts
4861   // readability with nested diamonds.
4862   const Operator* const merge_op = common()->Merge(2);
4863   const Operator* const phi_op =
4864       common()->Phi(MachineRepresentation::kWord32, 2);
4865 
4866   Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4867   Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
4868                                    graph()->start());
4869 
4870   Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4871   Node* true0 = zero;
4872 
4873   Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4874   Node* false0;
4875   {
4876     Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
4877 
4878     Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
4879     Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4880 
4881     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4882     Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
4883 
4884     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4885     Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
4886 
4887     if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4888     false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4889   }
4890 
4891   Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4892   return graph()->NewNode(phi_op, true0, false0, merge0);
4893 }
4894 
DoMax(Node * node,Operator const * op,MachineRepresentation rep)4895 void SimplifiedLowering::DoMax(Node* node, Operator const* op,
4896                                MachineRepresentation rep) {
4897   Node* const lhs = node->InputAt(0);
4898   Node* const rhs = node->InputAt(1);
4899 
4900   node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
4901   DCHECK_EQ(rhs, node->InputAt(1));
4902   node->AppendInput(graph()->zone(), lhs);
4903   ChangeOp(node, common()->Select(rep));
4904 }
4905 
DoMin(Node * node,Operator const * op,MachineRepresentation rep)4906 void SimplifiedLowering::DoMin(Node* node, Operator const* op,
4907                                MachineRepresentation rep) {
4908   Node* const lhs = node->InputAt(0);
4909   Node* const rhs = node->InputAt(1);
4910 
4911   node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
4912   DCHECK_EQ(lhs, node->InputAt(1));
4913   DCHECK_EQ(rhs, node->InputAt(2));
4914   ChangeOp(node, common()->Select(rep));
4915 }
4916 
DoIntegral32ToBit(Node * node)4917 void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
4918   Node* const input = node->InputAt(0);
4919   Node* const zero = jsgraph()->Int32Constant(0);
4920   Operator const* const op = machine()->Word32Equal();
4921 
4922   node->ReplaceInput(0, graph()->NewNode(op, input, zero));
4923   node->AppendInput(graph()->zone(), zero);
4924   ChangeOp(node, op);
4925 }
4926 
DoOrderedNumberToBit(Node * node)4927 void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
4928   Node* const input = node->InputAt(0);
4929 
4930   node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
4931                                          jsgraph()->Float64Constant(0.0)));
4932   node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
4933   ChangeOp(node, machine()->Word32Equal());
4934 }
4935 
DoNumberToBit(Node * node)4936 void SimplifiedLowering::DoNumberToBit(Node* node) {
4937   Node* const input = node->InputAt(0);
4938 
4939   node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
4940   node->AppendInput(graph()->zone(),
4941                     graph()->NewNode(machine()->Float64Abs(), input));
4942   ChangeOp(node, machine()->Float64LessThan());
4943 }
4944 
DoIntegerToUint8Clamped(Node * node)4945 void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
4946   Node* const input = node->InputAt(0);
4947   Node* const min = jsgraph()->Float64Constant(0.0);
4948   Node* const max = jsgraph()->Float64Constant(255.0);
4949 
4950   node->ReplaceInput(
4951       0, graph()->NewNode(machine()->Float64LessThan(), min, input));
4952   node->AppendInput(
4953       graph()->zone(),
4954       graph()->NewNode(
4955           common()->Select(MachineRepresentation::kFloat64),
4956           graph()->NewNode(machine()->Float64LessThan(), input, max), input,
4957           max));
4958   node->AppendInput(graph()->zone(), min);
4959   ChangeOp(node, common()->Select(MachineRepresentation::kFloat64));
4960 }
4961 
DoNumberToUint8Clamped(Node * node)4962 void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
4963   Node* const input = node->InputAt(0);
4964   Node* const min = jsgraph()->Float64Constant(0.0);
4965   Node* const max = jsgraph()->Float64Constant(255.0);
4966 
4967   node->ReplaceInput(
4968       0, graph()->NewNode(
4969              common()->Select(MachineRepresentation::kFloat64),
4970              graph()->NewNode(machine()->Float64LessThan(), min, input),
4971              graph()->NewNode(
4972                  common()->Select(MachineRepresentation::kFloat64),
4973                  graph()->NewNode(machine()->Float64LessThan(), input, max),
4974                  input, max),
4975              min));
4976   ChangeOp(node, machine()->Float64RoundTiesEven().placeholder());
4977 }
4978 
DoSigned32ToUint8Clamped(Node * node)4979 void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
4980   Node* const input = node->InputAt(0);
4981   Node* const min = jsgraph()->Int32Constant(0);
4982   Node* const max = jsgraph()->Int32Constant(255);
4983 
4984   node->ReplaceInput(
4985       0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
4986   node->AppendInput(
4987       graph()->zone(),
4988       graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
4989                        graph()->NewNode(machine()->Int32LessThan(), input, min),
4990                        min, input));
4991   node->AppendInput(graph()->zone(), max);
4992   ChangeOp(node, common()->Select(MachineRepresentation::kWord32));
4993 }
4994 
DoUnsigned32ToUint8Clamped(Node * node)4995 void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
4996   Node* const input = node->InputAt(0);
4997   Node* const max = jsgraph()->Uint32Constant(255u);
4998 
4999   node->ReplaceInput(
5000       0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
5001   node->AppendInput(graph()->zone(), input);
5002   node->AppendInput(graph()->zone(), max);
5003   ChangeOp(node, common()->Select(MachineRepresentation::kWord32));
5004 }
5005 
ToNumberCode()5006 Node* SimplifiedLowering::ToNumberCode() {
5007   if (!to_number_code_.is_set()) {
5008     Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumber);
5009     to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
5010   }
5011   return to_number_code_.get();
5012 }
5013 
ToNumberConvertBigIntCode()5014 Node* SimplifiedLowering::ToNumberConvertBigIntCode() {
5015   if (!to_number_convert_big_int_code_.is_set()) {
5016     Callable callable =
5017         Builtins::CallableFor(isolate(), Builtin::kToNumberConvertBigInt);
5018     to_number_convert_big_int_code_.set(
5019         jsgraph()->HeapConstant(callable.code()));
5020   }
5021   return to_number_convert_big_int_code_.get();
5022 }
5023 
ToNumericCode()5024 Node* SimplifiedLowering::ToNumericCode() {
5025   if (!to_numeric_code_.is_set()) {
5026     Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumeric);
5027     to_numeric_code_.set(jsgraph()->HeapConstant(callable.code()));
5028   }
5029   return to_numeric_code_.get();
5030 }
5031 
ToNumberOperator()5032 Operator const* SimplifiedLowering::ToNumberOperator() {
5033   if (!to_number_operator_.is_set()) {
5034     Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumber);
5035     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
5036     auto call_descriptor = Linkage::GetStubCallDescriptor(
5037         graph()->zone(), callable.descriptor(),
5038         callable.descriptor().GetStackParameterCount(), flags,
5039         Operator::kNoProperties);
5040     to_number_operator_.set(common()->Call(call_descriptor));
5041   }
5042   return to_number_operator_.get();
5043 }
5044 
ToNumberConvertBigIntOperator()5045 Operator const* SimplifiedLowering::ToNumberConvertBigIntOperator() {
5046   if (!to_number_convert_big_int_operator_.is_set()) {
5047     Callable callable =
5048         Builtins::CallableFor(isolate(), Builtin::kToNumberConvertBigInt);
5049     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
5050     auto call_descriptor = Linkage::GetStubCallDescriptor(
5051         graph()->zone(), callable.descriptor(),
5052         callable.descriptor().GetStackParameterCount(), flags,
5053         Operator::kNoProperties);
5054     to_number_convert_big_int_operator_.set(common()->Call(call_descriptor));
5055   }
5056   return to_number_convert_big_int_operator_.get();
5057 }
5058 
ToNumericOperator()5059 Operator const* SimplifiedLowering::ToNumericOperator() {
5060   if (!to_numeric_operator_.is_set()) {
5061     Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumeric);
5062     CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
5063     auto call_descriptor = Linkage::GetStubCallDescriptor(
5064         graph()->zone(), callable.descriptor(),
5065         callable.descriptor().GetStackParameterCount(), flags,
5066         Operator::kNoProperties);
5067     to_numeric_operator_.set(common()->Call(call_descriptor));
5068   }
5069   return to_numeric_operator_.get();
5070 }
5071 
ChangeOp(Node * node,const Operator * new_op)5072 void SimplifiedLowering::ChangeOp(Node* node, const Operator* new_op) {
5073   compiler::NodeProperties::ChangeOp(node, new_op);
5074 
5075   if (V8_UNLIKELY(observe_node_manager_ != nullptr))
5076     observe_node_manager_->OnNodeChanged(kSimplifiedLoweringReducerName, node,
5077                                          node);
5078 }
5079 
5080 #undef TRACE
5081 
5082 }  // namespace compiler
5083 }  // namespace internal
5084 }  // namespace v8
5085