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