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