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