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