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 33230 : MachineRepresentation MachineRepresentationFromArrayType(
70 : ExternalArrayType array_type) {
71 33230 : switch (array_type) {
72 : case kExternalUint8Array:
73 : case kExternalUint8ClampedArray:
74 : case kExternalInt8Array:
75 : return MachineRepresentation::kWord8;
76 : case kExternalUint16Array:
77 : case kExternalInt16Array:
78 5325 : return MachineRepresentation::kWord16;
79 : case kExternalUint32Array:
80 : case kExternalInt32Array:
81 6528 : return MachineRepresentation::kWord32;
82 : case kExternalFloat32Array:
83 7464 : return MachineRepresentation::kFloat32;
84 : case kExternalFloat64Array:
85 3086 : return MachineRepresentation::kFloat64;
86 : case kExternalBigInt64Array:
87 : case kExternalBigUint64Array:
88 0 : UNIMPLEMENTED();
89 : }
90 0 : UNREACHABLE();
91 : }
92 :
93 1092615 : UseInfo CheckedUseInfoAsWord32FromHint(
94 : NumberOperationHint hint, const VectorSlotPair& feedback = VectorSlotPair(),
95 : IdentifyZeros identify_zeros = kDistinguishZeros) {
96 1092615 : 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 190817 : UseInfo CheckedUseInfoAsFloat64FromHint(
111 : NumberOperationHint hint, const VectorSlotPair& feedback,
112 : IdentifyZeros identify_zeros = kDistinguishZeros) {
113 190817 : 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 9789294 : UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
129 9789294 : 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 6363000 : UseInfo UseInfoForBasePointer(const FieldAccess& access) {
155 12726002 : return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
156 : }
157 :
158 191797 : UseInfo UseInfoForBasePointer(const ElementAccess& access) {
159 383594 : return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
160 : }
161 :
162 365571 : void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
163 2122850 : for (Edge edge : node->use_edges()) {
164 878646 : if (NodeProperties::IsControlEdge(edge)) {
165 0 : edge.UpdateTo(control);
166 878649 : } else if (NodeProperties::IsEffectEdge(edge)) {
167 446205 : edge.UpdateTo(effect);
168 : } else {
169 : DCHECK(NodeProperties::IsValueEdge(edge) ||
170 : NodeProperties::IsContextEdge(edge));
171 : }
172 : }
173 365558 : }
174 :
175 311088 : 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 155561 : left = Type::Intersect(left, Type::Signed32(), type_zone);
181 155557 : right = Type::Intersect(right, Type::Signed32(), type_zone);
182 311090 : if (left.IsNone() || right.IsNone()) return false;
183 155527 : switch (op->opcode()) {
184 : case IrOpcode::kSpeculativeSafeIntegerAdd:
185 151459 : return (left.Max() + right.Max() > kMaxInt) ||
186 151461 : (left.Min() + right.Min() < kMinInt);
187 :
188 : case IrOpcode::kSpeculativeSafeIntegerSubtract:
189 16585 : return (left.Max() - right.Min() > kMaxInt) ||
190 16585 : (left.Min() - right.Max() < kMinInt);
191 :
192 : default:
193 0 : UNREACHABLE();
194 : }
195 : return true;
196 : }
197 :
198 8608 : bool IsSomePositiveOrderedNumber(Type type) {
199 14312 : 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 456110 : 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 88835152 : bool AddUse(UseInfo info) {
238 88835152 : Truncation old_truncation = truncation_;
239 88835152 : truncation_ = Truncation::Generalize(truncation_, info.truncation());
240 88834375 : return truncation_ != old_truncation;
241 : }
242 :
243 33362969 : void set_queued() { state_ = kQueued; }
244 61148196 : void set_visited() { state_ = kVisited; }
245 27787172 : void set_pushed() { state_ = kPushed; }
246 42889673 : 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 31736307 : void set_output(MachineRepresentation output) { representation_ = output; }
252 :
253 : MachineRepresentation representation() const { return representation_; }
254 :
255 : // Helpers for feedback typing.
256 19807020 : void set_feedback_type(Type type) { feedback_type_ = type; }
257 : Type feedback_type() const { return feedback_type_; }
258 92565 : void set_weakened() { weakened_ = true; }
259 : bool weakened() const { return weakened_; }
260 27883937 : 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 456110 : RepresentationSelector(JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
276 : RepresentationChanger* changer,
277 : SourcePositionTable* source_positions,
278 456126 : NodeOriginTable* node_origins)
279 : : jsgraph_(jsgraph),
280 : zone_(zone),
281 456110 : 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 456123 : type_cache_(TypeCache::Get()),
295 2280600 : op_typer_(broker, graph_zone()) {
296 456130 : }
297 :
298 : // Forward propagation of types from type feedback.
299 1368349 : void RunTypePropagationPhase() {
300 : // Run type propagation.
301 456099 : TRACE("--{Type propagation phase}--\n");
302 456125 : phase_ = RETYPE;
303 : ResetNodeInfoState();
304 :
305 : DCHECK(typing_stack_.empty());
306 912250 : typing_stack_.push({graph()->end(), 0});
307 456125 : GetInfo(graph()->end())->set_pushed();
308 55571163 : 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 282417457 : while (current.input_index < current.node->InputCount()) {
314 : Node* input = current.node->InputAt(current.input_index);
315 85867214 : NodeInfo* input_info = GetInfo(input);
316 85867214 : current.input_index++;
317 85867214 : if (input_info->unvisited()) {
318 : input_info->set_pushed();
319 54662350 : typing_stack_.push({input, 0});
320 : pushed_unvisited = true;
321 27331303 : break;
322 : }
323 : }
324 55115297 : if (pushed_unvisited) continue;
325 :
326 : // Process the top of the stack.
327 27786020 : Node* node = current.node;
328 : typing_stack_.pop();
329 : NodeInfo* info = GetInfo(node);
330 : info->set_visited();
331 27786020 : bool updated = UpdateFeedbackType(node);
332 27785950 : TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
333 27785950 : VisitNode(node, info->truncation(), nullptr);
334 27785633 : TRACE(" ==> output ");
335 27785633 : PrintOutputInfo(info);
336 27785619 : TRACE("\n");
337 27785991 : if (updated) {
338 180575768 : for (Node* const user : node->uses()) {
339 71893301 : if (GetInfo(user)->visited()) {
340 : GetInfo(user)->set_queued();
341 : queue_.push(user);
342 : }
343 : }
344 : }
345 : }
346 :
347 : // Process the revisit queue.
348 5101748 : while (!queue_.empty()) {
349 4645640 : Node* node = queue_.front();
350 : queue_.pop();
351 : NodeInfo* info = GetInfo(node);
352 : info->set_visited();
353 4645630 : bool updated = UpdateFeedbackType(node);
354 4645646 : TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
355 4645646 : VisitNode(node, info->truncation(), nullptr);
356 4645609 : TRACE(" ==> output ");
357 4645609 : PrintOutputInfo(info);
358 4645626 : TRACE("\n");
359 4645621 : if (updated) {
360 13712237 : for (Node* const user : node->uses()) {
361 5443611 : if (GetInfo(user)->visited()) {
362 : GetInfo(user)->set_queued();
363 : queue_.push(user);
364 : }
365 : }
366 : }
367 : }
368 456108 : }
369 :
370 : void ResetNodeInfoState() {
371 : // Clean up for the next phase.
372 43345798 : for (NodeInfo& info : info_) {
373 : info.reset_state();
374 : }
375 : }
376 :
377 : Type TypeOf(Node* node) {
378 : Type type = GetInfo(node)->feedback_type();
379 40130036 : return type.IsInvalid() ? NodeProperties::GetType(node) : type;
380 : }
381 :
382 : Type FeedbackTypeOf(Node* node) {
383 : Type type = GetInfo(node)->feedback_type();
384 33827156 : return type.IsInvalid() ? Type::None() : type;
385 : }
386 :
387 795522 : Type TypePhi(Node* node) {
388 795522 : int arity = node->op()->ValueInputCount();
389 : Type type = FeedbackTypeOf(node->InputAt(0));
390 1922306 : for (int i = 1; i < arity; ++i) {
391 1126782 : type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
392 : }
393 795524 : return type;
394 : }
395 :
396 13922 : Type TypeSelect(Node* node) {
397 : return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
398 13922 : FeedbackTypeOf(node->InputAt(2)));
399 : }
400 :
401 34787483 : bool UpdateFeedbackType(Node* node) {
402 32430825 : if (node->op()->ValueOutputCount() == 0) return false;
403 :
404 : NodeInfo* info = GetInfo(node);
405 : Type type = info->feedback_type();
406 23239319 : 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 23239319 : if (node->opcode() != IrOpcode::kPhi) {
412 130372060 : for (int i = 0; i < node->op()->ValueInputCount(); i++) {
413 54758580 : 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 39803101 : if (node->InputCount() > 0) input0_type = FeedbackTypeOf(node->InputAt(0));
423 : Type input1_type;
424 36929321 : if (node->InputCount() > 1) input1_type = FeedbackTypeOf(node->InputAt(1));
425 :
426 22444775 : 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 465754 : SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
433 12 : 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 353752 : 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 294 : 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 47759 : SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
460 : #undef DECLARE_CASE
461 :
462 : case IrOpcode::kConvertReceiver:
463 899 : new_type = op_typer_.ConvertReceiver(input0_type);
464 899 : break;
465 :
466 : case IrOpcode::kPlainPrimitiveToNumber:
467 1085 : new_type = op_typer_.ToNumber(input0_type);
468 1085 : break;
469 :
470 : case IrOpcode::kCheckBounds:
471 : new_type =
472 : Type::Intersect(op_typer_.CheckBounds(input0_type, input1_type),
473 59993 : info->restriction_type(), graph_zone());
474 59993 : break;
475 :
476 : case IrOpcode::kCheckFloat64Hole:
477 : new_type = Type::Intersect(op_typer_.CheckFloat64Hole(input0_type),
478 587 : info->restriction_type(), graph_zone());
479 587 : break;
480 :
481 : case IrOpcode::kCheckNumber:
482 : new_type = Type::Intersect(op_typer_.CheckNumber(input0_type),
483 572 : info->restriction_type(), graph_zone());
484 572 : break;
485 :
486 : case IrOpcode::kPhi: {
487 795514 : new_type = TypePhi(node);
488 795519 : if (!type.IsInvalid()) {
489 469350 : new_type = Weaken(node, type, new_type);
490 : }
491 : break;
492 : }
493 :
494 : case IrOpcode::kConvertTaggedHoleToUndefined:
495 : new_type = op_typer_.ConvertTaggedHoleToUndefined(
496 1858 : FeedbackTypeOf(node->InputAt(0)));
497 1858 : break;
498 :
499 : case IrOpcode::kTypeGuard: {
500 : new_type = op_typer_.TypeTypeGuard(node->op(),
501 32278 : FeedbackTypeOf(node->InputAt(0)));
502 32278 : break;
503 : }
504 :
505 : case IrOpcode::kSelect: {
506 13922 : new_type = TypeSelect(node);
507 13922 : break;
508 : }
509 :
510 : default:
511 : // Shortcut for operations that we do not handle.
512 20550780 : if (type.IsInvalid()) {
513 : GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
514 18131358 : 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 1893995 : new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());
523 :
524 2830956 : if (!type.IsInvalid() && new_type.Is(type)) return false;
525 : GetInfo(node)->set_feedback_type(new_type);
526 1675662 : 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 1780093 : Type Weaken(Node* node, Type previous_type, Type current_type) {
554 : // If the types have nothing to do with integers, return the types.
555 469350 : Type const integer = type_cache_->kInteger;
556 469350 : if (!previous_type.Maybe(integer)) {
557 30977 : return current_type;
558 : }
559 : DCHECK(current_type.Maybe(integer));
560 :
561 438374 : Type current_integer = Type::Intersect(current_type, integer, graph_zone());
562 : DCHECK(!current_integer.IsNone());
563 : Type previous_integer =
564 438371 : 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 438374 : 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 96941 : Type previous = previous_integer.GetRange();
573 96941 : Type current = current_integer.GetRange();
574 189605 : if (current.IsInvalid() || previous.IsInvalid()) {
575 4375 : 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 433998 : graph_zone());
584 : }
585 :
586 : // Backward propagation of truncations.
587 456122 : void RunTruncationPropagationPhase() {
588 : // Run propagation phase to a fixpoint.
589 456122 : TRACE("--{Propagation phase}--\n");
590 456122 : phase_ = PROPAGATE;
591 456122 : EnqueueInitial(jsgraph_->graph()->end());
592 : // Process nodes from the queue until it is empty.
593 29628784 : while (!queue_.empty()) {
594 28716532 : Node* node = queue_.front();
595 : NodeInfo* info = GetInfo(node);
596 : queue_.pop();
597 : info->set_visited();
598 28716546 : TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
599 : info->truncation().description());
600 28716546 : VisitNode(node, info->truncation(), nullptr);
601 : }
602 456130 : }
603 :
604 456122 : void Run(SimplifiedLowering* lowering) {
605 456122 : RunTruncationPropagationPhase();
606 :
607 456130 : RunTypePropagationPhase();
608 :
609 : // Run lowering and change insertion phase.
610 456112 : TRACE("--{Simplified lowering phase}--\n");
611 456123 : phase_ = LOWER;
612 : // Process nodes from the collected {nodes_} vector.
613 28698007 : for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
614 27785751 : Node* node = *i;
615 : NodeInfo* info = GetInfo(node);
616 27785751 : 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 27785751 : source_positions_, source_positions_->GetSourcePosition(node));
620 : NodeOriginTable::Scope origin_scope(node_origins_, "simplified lowering",
621 27785841 : node);
622 27785841 : VisitNode(node, info->truncation(), lowering);
623 : }
624 :
625 : // Perform the final replacements.
626 2298680 : for (NodeVector::iterator i = replacements_.begin();
627 : i != replacements_.end(); ++i) {
628 1386428 : Node* node = *i;
629 1386428 : Node* replacement = *(++i);
630 1386428 : node->ReplaceUses(replacement);
631 1386401 : node->Kill();
632 : // We also need to replace the node in the rest of the vector.
633 379856170 : for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
634 : ++j;
635 377083342 : if (*j == node) *j = replacement;
636 : }
637 : }
638 456119 : }
639 :
640 456122 : void EnqueueInitial(Node* node) {
641 456122 : NodeInfo* info = GetInfo(node);
642 : info->set_queued();
643 456122 : nodes_.push_back(node);
644 : queue_.push(node);
645 456122 : }
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 139425014 : void EnqueueInput(Node* use_node, int index,
651 : UseInfo use_info = UseInfo::None()) {
652 139425014 : Node* node = use_node->InputAt(index);
653 217339871 : if (phase_ != PROPAGATE) return;
654 90446420 : 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 88839549 : if (info->unvisited()) {
661 : // First visit of this node.
662 : info->set_queued();
663 27329822 : nodes_.push_back(node);
664 : queue_.push(node);
665 27329771 : TRACE(" initial #%i: ", node->id());
666 27329771 : info->AddUse(use_info);
667 27329547 : PrintTruncation(info->truncation());
668 27329392 : return;
669 : }
670 61509727 : TRACE(" queue #%i?: ", node->id());
671 61509727 : PrintTruncation(info->truncation());
672 61509436 : if (info->AddUse(use_info)) {
673 : // New usage information for the node is available.
674 1606871 : if (!info->queued()) {
675 : queue_.push(node);
676 : info->set_queued();
677 931315 : TRACE(" added: ");
678 : } else {
679 675557 : TRACE(" inqueue: ");
680 : }
681 1606872 : 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 86798156 : 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 94674 : bool InputCannotBe(Node* node, Type type) {
712 : DCHECK_EQ(1, node->op()->ValueInputCount());
713 94674 : return !GetUpperBound(node->InputAt(0)).Maybe(type);
714 : }
715 :
716 54852 : bool InputIs(Node* node, Type type) {
717 : DCHECK_EQ(1, node->op()->ValueInputCount());
718 109704 : return GetUpperBound(node->InputAt(0)).Is(type);
719 : }
720 :
721 : bool BothInputsAreSigned32(Node* node) {
722 93602 : return BothInputsAre(node, Type::Signed32());
723 : }
724 :
725 : bool BothInputsAreUnsigned32(Node* node) {
726 100225 : return BothInputsAre(node, Type::Unsigned32());
727 : }
728 :
729 1035595 : bool BothInputsAre(Node* node, Type type) {
730 : DCHECK_EQ(2, node->op()->ValueInputCount());
731 3431475 : return GetUpperBound(node->InputAt(0)).Is(type) &&
732 2395880 : GetUpperBound(node->InputAt(1)).Is(type);
733 : }
734 :
735 : bool IsNodeRepresentationTagged(Node* node) {
736 33569 : 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 773637 : void ChangeToPureOp(Node* node, const Operator* new_op) {
747 : DCHECK(new_op->HasProperty(Operator::kPure));
748 692426 : if (node->op()->EffectInputCount() > 0) {
749 : DCHECK_LT(0, node->op()->ControlInputCount());
750 213573 : Node* control = NodeProperties::GetControlInput(node);
751 213567 : Node* effect = NodeProperties::GetEffectInput(node);
752 213554 : 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 610 : jsgraph_->common()->Unreachable(), effect, control);
759 610 : new_op = jsgraph_->common()->DeadValue(GetInfo(node)->representation());
760 305 : node->ReplaceInput(0, unreachable);
761 : }
762 : // Rewire the effect and control chains.
763 213554 : node->TrimInputCount(new_op->ValueInputCount());
764 213565 : ReplaceEffectControlUses(node, effect, control);
765 : } else {
766 : DCHECK_EQ(0, node->op()->ControlInputCount());
767 : }
768 346212 : NodeProperties::ChangeOp(node, new_op);
769 346200 : }
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 63317227 : 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 47963947 : if (use.representation() == MachineRepresentation::kNone)
779 47963814 : return; // No input requirement on the use.
780 : DCHECK_NOT_NULL(input);
781 60708647 : NodeInfo* input_info = GetInfo(input);
782 : MachineRepresentation input_rep = input_info->representation();
783 75465935 : if (input_rep != use.representation() ||
784 30110552 : use.type_check() != TypeCheckKind::kNone) {
785 : // Output representation doesn't match usage.
786 15353322 : TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
787 : index, input->id(), input->op()->mnemonic());
788 15353307 : TRACE(" from ");
789 15353307 : PrintOutputInfo(input_info);
790 15353280 : TRACE(" to ");
791 15353280 : PrintUseInfo(use);
792 15353253 : TRACE("\n");
793 15353264 : if (input_type.IsInvalid()) {
794 : input_type = TypeOf(input);
795 : }
796 : Node* n = changer_->GetRepresentationFor(
797 15353264 : input, input_info->representation(), input_type, node, use);
798 15353185 : node->ReplaceInput(index, n);
799 : }
800 : }
801 :
802 155461353 : void ProcessInput(Node* node, int index, UseInfo use) {
803 155461353 : switch (phase_) {
804 : case PROPAGATE:
805 49755960 : EnqueueInput(node, index, use);
806 49754126 : break;
807 : case RETYPE:
808 : break;
809 : case LOWER:
810 47943318 : ConvertInput(node, index, use);
811 47943173 : break;
812 : }
813 155459374 : }
814 :
815 15127416 : void ProcessRemainingInputs(Node* node, int index) {
816 : DCHECK_GE(index, NodeProperties::PastValueIndex(node));
817 : DCHECK_GE(index, NodeProperties::PastContextIndex(node));
818 62590118 : for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
819 23731377 : i < NodeProperties::PastEffectIndex(node); ++i) {
820 8603983 : EnqueueInput(node, i); // Effect inputs: just visit
821 : }
822 62705518 : for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
823 23789066 : i < NodeProperties::PastControlIndex(node); ++i) {
824 8661666 : EnqueueInput(node, i); // Control inputs: just visit
825 : }
826 15127413 : }
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 53378092 : void VisitInputs(Node* node) {
833 53378092 : int tagged_count = node->op()->ValueInputCount() +
834 : OperatorProperties::GetContextInputCount(node->op()) +
835 26688693 : OperatorProperties::GetFrameStateInputCount(node->op());
836 : // Visit value, context and frame state inputs as tagged.
837 63054632 : for (int i = 0; i < tagged_count; i++) {
838 36365937 : ProcessInput(node, i, UseInfo::AnyTagged());
839 : }
840 : // Only enqueue other inputs (effects, control).
841 126697364 : for (int i = tagged_count; i < node->InputCount(); i++) {
842 50004211 : EnqueueInput(node, i);
843 : }
844 26688858 : }
845 :
846 3251780 : void VisitReturn(Node* node) {
847 3251780 : int tagged_limit = node->op()->ValueInputCount() +
848 : OperatorProperties::GetContextInputCount(node->op()) +
849 1625910 : OperatorProperties::GetFrameStateInputCount(node->op());
850 : // Visit integer slot count to pop
851 1625906 : ProcessInput(node, 0, UseInfo::TruncatingWord32());
852 :
853 : // Visit value, context and frame state inputs as tagged.
854 3251751 : for (int i = 1; i < tagged_limit; i++) {
855 1625887 : ProcessInput(node, i, UseInfo::AnyTagged());
856 : }
857 : // Only enqueue other inputs (effects, control).
858 8129444 : for (int i = tagged_limit; i < node->InputCount(); i++) {
859 3251772 : EnqueueInput(node, i);
860 : }
861 1625904 : }
862 :
863 : // Helper for an unused node.
864 976203 : void VisitUnused(Node* node) {
865 650799 : int value_count = node->op()->ValueInputCount() +
866 : OperatorProperties::GetContextInputCount(node->op()) +
867 325403 : OperatorProperties::GetFrameStateInputCount(node->op());
868 828743 : for (int i = 0; i < value_count; i++) {
869 503340 : ProcessInput(node, i, UseInfo::None());
870 : }
871 325404 : ProcessRemainingInputs(node, value_count);
872 325404 : if (lower()) Kill(node);
873 325404 : }
874 :
875 : // Helper for no-op node.
876 66 : void VisitNoop(Node* node, Truncation truncation) {
877 80 : if (truncation.IsUnused()) return VisitUnused(node);
878 : MachineRepresentation representation =
879 26 : GetOutputInfoForPhi(node, TypeOf(node), truncation);
880 52 : VisitUnop(node, UseInfo(representation, truncation), representation);
881 39 : if (lower()) DeferReplacement(node, node->InputAt(0));
882 : }
883 :
884 : // Helper for binops of the R x L -> O variety.
885 3538999 : 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 3538999 : ProcessInput(node, 0, left_use);
890 3538455 : ProcessInput(node, 1, right_use);
891 13823350 : for (int i = 2; i < node->InputCount(); i++) {
892 3373391 : EnqueueInput(node, i);
893 : }
894 : SetOutput(node, output, restriction_type);
895 3538201 : }
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 2860384 : VisitBinop(node, input_use, input_use, output, restriction_type);
901 : }
902 :
903 103183 : void VisitSpeculativeInt32Binop(Node* node) {
904 : DCHECK_EQ(2, node->op()->ValueInputCount());
905 85638 : if (BothInputsAre(node, Type::NumberOrOddball())) {
906 : return VisitBinop(node, UseInfo::TruncatingWord32(),
907 : MachineRepresentation::kWord32);
908 : }
909 17545 : NumberOperationHint hint = NumberOperationHintOf(node->op());
910 : return VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
911 35090 : MachineRepresentation::kWord32);
912 : }
913 :
914 : // Helper for unops of the I -> O variety.
915 9165155 : void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output,
916 : Type restriction_type = Type::Any()) {
917 : DCHECK_EQ(1, node->op()->ValueInputCount());
918 9165155 : ProcessInput(node, 0, input_use);
919 9165174 : ProcessRemainingInputs(node, 1);
920 : SetOutput(node, output, restriction_type);
921 9165169 : }
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 634181 : void VisitFloat64Binop(Node* node) {
931 : VisitBinop(node, UseInfo::TruncatingFloat64(),
932 : MachineRepresentation::kFloat64);
933 634195 : }
934 8290 : void VisitInt64Binop(Node* node) {
935 : VisitBinop(node, UseInfo::Word64(), MachineRepresentation::kWord64);
936 8290 : }
937 488041 : void VisitWord32TruncatingBinop(Node* node) {
938 : VisitBinop(node, UseInfo::TruncatingWord32(),
939 : MachineRepresentation::kWord32);
940 488037 : }
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 1660202 : MachineRepresentation GetOutputInfoForPhi(Node* node, Type type,
947 1151391 : Truncation use) {
948 : // Compute the representation.
949 1660159 : if (type.Is(Type::None())) {
950 : return MachineRepresentation::kNone;
951 2967357 : } else if (type.Is(Type::Signed32()) || type.Is(Type::Unsigned32())) {
952 : return MachineRepresentation::kWord32;
953 2137698 : } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
954 : return MachineRepresentation::kWord32;
955 1310767 : } else if (type.Is(Type::Boolean())) {
956 : return MachineRepresentation::kBit;
957 1951152 : } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsFloat64()) {
958 : return MachineRepresentation::kFloat64;
959 2302797 : } 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 1151230 : } else if (type.Is(Type::Number())) {
966 : return MachineRepresentation::kFloat64;
967 511328 : } else if (type.Is(Type::ExternalPointer())) {
968 : return MachineType::PointerRepresentation();
969 : }
970 511328 : return MachineRepresentation::kTagged;
971 : }
972 :
973 : // Helper for handling selects.
974 56599 : void VisitSelect(Node* node, Truncation truncation,
975 42677 : SimplifiedLowering* lowering) {
976 : DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
977 42677 : ProcessInput(node, 0, UseInfo::Bool());
978 :
979 : MachineRepresentation output =
980 42677 : GetOutputInfoForPhi(node, TypeOf(node), truncation);
981 : SetOutput(node, output);
982 :
983 42677 : if (lower()) {
984 : // Update the select operator.
985 13922 : SelectParameters p = SelectParametersOf(node->op());
986 13922 : if (output != p.representation()) {
987 : NodeProperties::ChangeOp(node,
988 6859 : 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 85354 : UseInfo input_use(output, truncation);
994 42677 : ProcessInput(node, 1, input_use);
995 42677 : ProcessInput(node, 2, input_use);
996 42677 : }
997 :
998 : // Helper for handling phis.
999 3062551 : void VisitPhi(Node* node, Truncation truncation,
1000 1531269 : SimplifiedLowering* lowering) {
1001 : MachineRepresentation output =
1002 1531282 : 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 1531269 : int values = node->op()->ValueInputCount();
1008 1531269 : if (lower()) {
1009 : // Update the phi operator.
1010 326183 : if (output != PhiRepresentationOf(node->op())) {
1011 179881 : 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 3062535 : UseInfo input_use(output, truncation);
1018 14034634 : for (int i = 0; i < node->InputCount(); i++) {
1019 10972317 : ProcessInput(node, i, i < values ? input_use : UseInfo::None());
1020 : }
1021 1531341 : }
1022 :
1023 307082 : void VisitObjectIs(Node* node, Type type, SimplifiedLowering* lowering) {
1024 152628 : Type const input_type = TypeOf(node->InputAt(0));
1025 152627 : if (input_type.Is(type)) {
1026 4098 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
1027 4098 : if (lower()) {
1028 1398 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
1029 : }
1030 : } else {
1031 148531 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
1032 148532 : if (lower() && !input_type.Maybe(type)) {
1033 426 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1034 : }
1035 : }
1036 152629 : }
1037 :
1038 31206 : void VisitCheck(Node* node, Type type, SimplifiedLowering* lowering) {
1039 30961 : if (InputIs(node, type)) {
1040 : VisitUnop(node, UseInfo::AnyTagged(),
1041 245 : MachineRepresentation::kTaggedPointer);
1042 310 : if (lower()) DeferReplacement(node, node->InputAt(0));
1043 : } else {
1044 : VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
1045 30716 : MachineRepresentation::kTaggedPointer);
1046 : }
1047 30961 : }
1048 :
1049 1745783 : void VisitCall(Node* node, SimplifiedLowering* lowering) {
1050 1745791 : auto call_descriptor = CallDescriptorOf(node->op());
1051 872890 : int params = static_cast<int>(call_descriptor->ParameterCount());
1052 872890 : int value_input_count = node->op()->ValueInputCount();
1053 : // Propagate representation information from call descriptor.
1054 8143564 : for (int i = 0; i < value_input_count; i++) {
1055 7270656 : if (i == 0) {
1056 : // The target of the call.
1057 872897 : ProcessInput(node, i, UseInfo::Any());
1058 6397771 : } else if ((i - 1) < params) {
1059 : ProcessInput(node, i,
1060 : TruncatingUseInfoFromRepresentation(
1061 11059454 : call_descriptor->GetInputType(i).representation()));
1062 : } else {
1063 868041 : ProcessInput(node, i, UseInfo::AnyTagged());
1064 : }
1065 : }
1066 872908 : ProcessRemainingInputs(node, value_input_count);
1067 :
1068 872898 : if (call_descriptor->ReturnCount() > 0) {
1069 : SetOutput(node, call_descriptor->GetReturnType(0).representation());
1070 : } else {
1071 : SetOutput(node, MachineRepresentation::kTagged);
1072 : }
1073 872898 : }
1074 :
1075 19217 : void MaskShiftOperand(Node* node, Type rhs_type) {
1076 28968 : if (!rhs_type.Is(type_cache_->kZeroToThirtyOne)) {
1077 4733 : Node* const rhs = NodeProperties::GetValueInput(node, 1);
1078 : node->ReplaceInput(1,
1079 : graph()->NewNode(jsgraph_->machine()->Word32And(), rhs,
1080 9466 : jsgraph_->Int32Constant(0x1F)));
1081 : }
1082 14484 : }
1083 :
1084 527639 : static MachineSemantic DeoptValueSemanticOf(Type type) {
1085 : // We only need signedness to do deopt correctly.
1086 527633 : if (type.Is(Type::Signed32())) {
1087 : return MachineSemantic::kInt32;
1088 356192 : } else if (type.Is(Type::Unsigned32())) {
1089 : return MachineSemantic::kUint32;
1090 : } else {
1091 354046 : return MachineSemantic::kAny;
1092 : }
1093 : }
1094 :
1095 9936305 : static MachineType DeoptMachineTypeOf(MachineRepresentation rep, Type type) {
1096 9936305 : if (type.IsNone()) {
1097 : return MachineType::None();
1098 : }
1099 : // Do not distinguish between various Tagged variations.
1100 9936303 : if (IsAnyTagged(rep)) {
1101 : return MachineType::AnyTagged();
1102 : }
1103 : // Word64 representation is only valid for safe integer values.
1104 528149 : if (rep == MachineRepresentation::kWord64) {
1105 : DCHECK(type.Is(TypeCache::Get()->kSafeInteger));
1106 510 : return MachineType(rep, MachineSemantic::kInt64);
1107 : }
1108 527639 : 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 527634 : return machine_type;
1115 : }
1116 :
1117 11822420 : void VisitStateValues(Node* node) {
1118 9228990 : if (propagate()) {
1119 20736399 : for (int i = 0; i < node->InputCount(); i++) {
1120 9071522 : EnqueueInput(node, i, UseInfo::Any());
1121 : }
1122 6635617 : } else if (lower()) {
1123 5186881 : Zone* zone = jsgraph_->zone();
1124 : ZoneVector<MachineType>* types =
1125 : new (zone->New(sizeof(ZoneVector<MachineType>)))
1126 2593457 : ZoneVector<MachineType>(node->InputCount(), zone);
1127 23329850 : for (int i = 0; i < node->InputCount(); i++) {
1128 : Node* input = node->InputAt(i);
1129 9071495 : (*types)[i] =
1130 9071495 : DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1131 : }
1132 2593430 : SparseInputMask mask = SparseInputMaskOf(node->op());
1133 : NodeProperties::ChangeOp(
1134 5186848 : node, jsgraph_->common()->TypedStateValues(types, mask));
1135 : }
1136 : SetOutput(node, MachineRepresentation::kTagged);
1137 9228972 : }
1138 :
1139 29941953 : void VisitFrameState(Node* node) {
1140 : DCHECK_EQ(5, node->op()->ValueInputCount());
1141 : DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
1142 :
1143 14970990 : ProcessInput(node, 0, UseInfo::AnyTagged()); // Parameters.
1144 14971010 : 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 14970991 : if (propagate()) {
1150 4741151 : EnqueueInput(node, 2, UseInfo::Any());
1151 10229844 : } else if (lower()) {
1152 6206463 : Zone* zone = jsgraph_->zone();
1153 : Node* accumulator = node->InputAt(2);
1154 4741175 : if (accumulator == jsgraph_->OptimizedOutConstant()) {
1155 4008504 : node->ReplaceInput(2, jsgraph_->SingleDeadTypedStateValues());
1156 : } else {
1157 : ZoneVector<MachineType>* types =
1158 : new (zone->New(sizeof(ZoneVector<MachineType>)))
1159 732645 : ZoneVector<MachineType>(1, zone);
1160 732645 : (*types)[0] = DeoptMachineTypeOf(GetInfo(accumulator)->representation(),
1161 732645 : TypeOf(accumulator));
1162 :
1163 : node->ReplaceInput(
1164 : 2, jsgraph_->graph()->NewNode(jsgraph_->common()->TypedStateValues(
1165 : types, SparseInputMask::Dense()),
1166 2197934 : accumulator));
1167 : }
1168 : }
1169 :
1170 14971027 : ProcessInput(node, 3, UseInfo::AnyTagged()); // Context.
1171 14971014 : ProcessInput(node, 4, UseInfo::AnyTagged()); // Closure.
1172 14971022 : ProcessInput(node, 5, UseInfo::AnyTagged()); // Outer frame state.
1173 14971018 : return SetOutput(node, MachineRepresentation::kTagged);
1174 : }
1175 :
1176 93314 : void VisitObjectState(Node* node) {
1177 70771 : if (propagate()) {
1178 286869 : for (int i = 0; i < node->InputCount(); i++) {
1179 132163 : EnqueueInput(node, i, UseInfo::Any());
1180 : }
1181 48228 : } else if (lower()) {
1182 45086 : Zone* zone = jsgraph_->zone();
1183 : ZoneVector<MachineType>* types =
1184 : new (zone->New(sizeof(ZoneVector<MachineType>)))
1185 22543 : ZoneVector<MachineType>(node->InputCount(), zone);
1186 309416 : for (int i = 0; i < node->InputCount(); i++) {
1187 : Node* input = node->InputAt(i);
1188 132165 : (*types)[i] =
1189 132165 : DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1190 : }
1191 : NodeProperties::ChangeOp(node, jsgraph_->common()->TypedObjectState(
1192 45086 : ObjectIdOf(node->op()), types));
1193 : }
1194 : SetOutput(node, MachineRepresentation::kTagged);
1195 70769 : }
1196 :
1197 213790 : const Operator* Int32Op(Node* node) {
1198 213790 : return changer_->Int32OperatorFor(node->opcode());
1199 : }
1200 :
1201 151698 : const Operator* Int32OverflowOp(Node* node) {
1202 151698 : return changer_->Int32OverflowOperatorFor(node->opcode());
1203 : }
1204 :
1205 2535 : const Operator* Int64Op(Node* node) {
1206 2535 : return changer_->Int64OperatorFor(node->opcode());
1207 : }
1208 :
1209 40098 : const Operator* Uint32Op(Node* node) {
1210 40098 : return changer_->Uint32OperatorFor(node->opcode());
1211 : }
1212 :
1213 107 : const Operator* Uint32OverflowOp(Node* node) {
1214 107 : return changer_->Uint32OverflowOperatorFor(node->opcode());
1215 : }
1216 :
1217 133333 : const Operator* Float64Op(Node* node) {
1218 173909 : return changer_->Float64OperatorFor(node->opcode());
1219 : }
1220 :
1221 4244083 : WriteBarrierKind WriteBarrierKindFor(
1222 : BaseTaggedness base_taggedness,
1223 : MachineRepresentation field_representation, Type field_type,
1224 : MachineRepresentation value_representation, Node* value) {
1225 8400593 : if (base_taggedness == kTaggedBase &&
1226 : CanBeTaggedPointer(field_representation)) {
1227 3428053 : Type value_type = NodeProperties::GetType(value);
1228 6856106 : if (field_representation == MachineRepresentation::kTaggedSigned ||
1229 3428053 : value_representation == MachineRepresentation::kTaggedSigned) {
1230 : // Write barriers are only for stores of heap objects.
1231 : return kNoWriteBarrier;
1232 : }
1233 6856108 : 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 3050875 : if (value_type.IsHeapConstant()) {
1240 : RootIndex root_index;
1241 1813040 : const RootsTable& roots_table = jsgraph_->isolate()->roots_table();
1242 1813040 : if (roots_table.IsRootHandle(value_type.AsHeapConstant()->Value(),
1243 1813040 : &root_index)) {
1244 1015026 : if (RootsTable::IsImmortalImmovable(root_index)) {
1245 : // Write barriers are unnecessary for immortal immovable roots.
1246 : return kNoWriteBarrier;
1247 : }
1248 : }
1249 : }
1250 4071696 : if (field_representation == MachineRepresentation::kTaggedPointer ||
1251 2035848 : value_representation == MachineRepresentation::kTaggedPointer) {
1252 : // Write barriers for heap objects are cheaper.
1253 : return kPointerWriteBarrier;
1254 : }
1255 : NumberMatcher m(value);
1256 1101501 : if (m.HasValue()) {
1257 2683 : 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 2683 : return kPointerWriteBarrier;
1263 : }
1264 : return kFullWriteBarrier;
1265 : }
1266 : return kNoWriteBarrier;
1267 : }
1268 :
1269 4121257 : 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 4121257 : value_representation, value);
1277 4121257 : if (write_barrier_kind != kNoWriteBarrier) {
1278 3971056 : if (base_taggedness == kTaggedBase &&
1279 1985528 : field_offset == HeapObject::kMapOffset) {
1280 : write_barrier_kind = kMapWriteBarrier;
1281 : }
1282 : }
1283 4121257 : return write_barrier_kind;
1284 : }
1285 :
1286 918393 : Graph* graph() const { return jsgraph_->graph(); }
1287 1105 : CommonOperatorBuilder* common() const { return jsgraph_->common(); }
1288 : SimplifiedOperatorBuilder* simplified() const {
1289 53129 : return jsgraph_->simplified();
1290 : }
1291 :
1292 5975 : void LowerToCheckedInt32Mul(Node* node, Truncation truncation,
1293 5975 : 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 4317 : truncation.IdentifiesZeroAndMinusZero() ||
1298 8608 : IsSomePositiveOrderedNumber(input0_type) ||
1299 4291 : IsSomePositiveOrderedNumber(input1_type)
1300 : ? CheckForMinusZeroMode::kDontCheckForMinusZero
1301 5975 : : CheckForMinusZeroMode::kCheckForMinusZero;
1302 :
1303 5975 : NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
1304 5975 : }
1305 :
1306 151698 : void ChangeToInt32OverflowOp(Node* node) {
1307 151699 : NodeProperties::ChangeOp(node, Int32OverflowOp(node));
1308 151697 : }
1309 :
1310 107 : void ChangeToUint32OverflowOp(Node* node) {
1311 107 : NodeProperties::ChangeOp(node, Uint32OverflowOp(node));
1312 107 : }
1313 :
1314 2454676 : void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation,
1315 1011419 : SimplifiedLowering* lowering) {
1316 803718 : Type left_upper = GetUpperBound(node->InputAt(0));
1317 803718 : Type right_upper = GetUpperBound(node->InputAt(1));
1318 :
1319 1961333 : if (left_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1320 353912 : 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 347870 : 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 726144 : if (GetUpperBound(node).Is(Type::Signed32()) ||
1329 396291 : GetUpperBound(node).Is(Type::Unsigned32()) ||
1330 : truncation.IsUsedAsWord32()) {
1331 : // => Int32Add/Sub
1332 266763 : VisitWord32TruncatingBinop(node);
1333 331080 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1334 : return;
1335 : }
1336 : }
1337 :
1338 : // Try to use type feedback.
1339 518645 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1340 : DCHECK(hint == NumberOperationHint::kSignedSmall ||
1341 : hint == NumberOperationHint::kSigned32);
1342 :
1343 518843 : Type left_feedback_type = TypeOf(node->InputAt(0));
1344 518843 : 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 518843 : : Type::Signed32();
1354 585837 : if (left_upper.Is(left_constraint_type) &&
1355 579659 : 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 457908 : IdentifyZeros left_identify_zeros = truncation.identify_zeros();
1365 900969 : if (node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd &&
1366 443025 : !right_feedback_type.Maybe(Type::MinusZero())) {
1367 : left_identify_zeros = kIdentifyZeros;
1368 : }
1369 : UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
1370 457944 : 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 458075 : kIdentifyZeros);
1377 : VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32,
1378 458026 : Type::Signed32());
1379 : }
1380 518926 : if (lower()) {
1381 311701 : if (truncation.IsUsedAsWord32() ||
1382 : !CanOverflowSigned32(node->op(), left_feedback_type,
1383 155562 : right_feedback_type, graph_zone())) {
1384 5848 : ChangeToPureOp(node, Int32Op(node));
1385 :
1386 : } else {
1387 150291 : ChangeToInt32OverflowOp(node);
1388 : }
1389 : }
1390 : return;
1391 : }
1392 :
1393 4014 : void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
1394 5156 : SimplifiedLowering* lowering) {
1395 12042 : if (BothInputsAre(node, type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1396 4014 : (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 8028 : MachineRepresentation::kFloat64, Type::Number());
1410 4014 : if (lower()) {
1411 1142 : ChangeToPureOp(node, Float64Op(node));
1412 : }
1413 : return;
1414 : }
1415 :
1416 18395 : void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
1417 12803 : SimplifiedLowering* lowering) {
1418 38410 : if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1419 147 : (truncation.IsUsedAsWord32() ||
1420 12888 : NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1421 : // => unsigned Uint32Mod
1422 643 : VisitWord32TruncatingBinop(node);
1423 643 : if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1424 : return;
1425 : }
1426 42003 : if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1427 1239 : (truncation.IsUsedAsWord32() ||
1428 14429 : 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 5801 : 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 5801 : 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 5669 : if (BothInputsAre(node, Type::Signed32())) {
1453 : // If both the inputs the feedback are int32, use the overflow op.
1454 2214 : if (hint == NumberOperationHint::kSignedSmall ||
1455 1107 : hint == NumberOperationHint::kSigned32) {
1456 : VisitBinop(node, UseInfo::TruncatingWord32(),
1457 : MachineRepresentation::kWord32, Type::Signed32());
1458 1107 : if (lower()) ChangeToInt32OverflowOp(node);
1459 : return;
1460 : }
1461 : }
1462 :
1463 9124 : if (hint == NumberOperationHint::kSignedSmall ||
1464 4562 : 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 3762 : hint, VectorSlotPair(), truncation.identify_zeros());
1472 : UseInfo const rhs_use = CheckedUseInfoAsWord32FromHint(
1473 3762 : hint, VectorSlotPair(), kIdentifyZeros);
1474 3762 : if (truncation.IsUsedAsWord32()) {
1475 207 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
1476 207 : if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1477 3555 : } 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 3555 : Type::Signed32());
1484 3555 : if (lower()) ChangeToInt32OverflowOp(node);
1485 : }
1486 : return;
1487 : }
1488 :
1489 1652 : if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
1490 1652 : TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
1491 0 : (truncation.IsUsedAsWord32() ||
1492 800 : 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 1719 : if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
1499 1719 : TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
1500 0 : (truncation.IsUsedAsWord32() ||
1501 800 : 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 1600 : truncation.identify_zeros(), VectorSlotPair());
1515 : UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1516 1600 : kIdentifyZeros, VectorSlotPair());
1517 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
1518 800 : Type::Number());
1519 1009 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1520 : return;
1521 : }
1522 :
1523 27787970 : 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 74659350 : if (node->op()->ValueOutputCount() > 0 &&
1528 23652501 : node->op()->EffectOutputCount() > 0 &&
1529 32349690 : node->opcode() != IrOpcode::kUnreachable && TypeOf(node).IsNone()) {
1530 1105 : Node* control = node->op()->ControlOutputCount() > 0
1531 : ? node
1532 1105 : : NodeProperties::GetControlInput(node, 0);
1533 :
1534 : Node* unreachable =
1535 1105 : graph()->NewNode(common()->Unreachable(), node, control);
1536 :
1537 : // Insert unreachable node and replace all the effect uses of the {node}
1538 : // with the new unreachable node.
1539 8124 : for (Edge edge : node->use_edges()) {
1540 5167 : if (NodeProperties::IsEffectEdge(edge) && edge.from() != unreachable) {
1541 1105 : edge.UpdateTo(unreachable);
1542 : }
1543 : }
1544 : }
1545 27785760 : }
1546 :
1547 397063 : void VisitCheckBounds(Node* node, SimplifiedLowering* lowering) {
1548 175392 : CheckParameters const& p = CheckParametersOf(node->op());
1549 175392 : Type const index_type = TypeOf(node->InputAt(0));
1550 175392 : Type const length_type = TypeOf(node->InputAt(1));
1551 175392 : if (length_type.Is(Type::Unsigned31())) {
1552 174802 : if (index_type.Is(Type::Integral32OrMinusZero())) {
1553 : // Map -0 to 0, and the values in the [-2^31,-1] range to the
1554 : // [2^31,2^32-1] range, which will be considered out-of-bounds
1555 : // as well, because the {length_type} is limited to Unsigned31.
1556 : VisitBinop(node, UseInfo::TruncatingWord32(),
1557 : MachineRepresentation::kWord32);
1558 160853 : if (lower()) {
1559 96060 : if (lowering->poisoning_level_ ==
1560 96060 : PoisoningMitigationLevel::kDontPoison &&
1561 96060 : (index_type.IsNone() || length_type.IsNone() ||
1562 92741 : (index_type.Min() >= 0.0 &&
1563 44711 : index_type.Max() < length_type.Min()))) {
1564 : // The bounds check is redundant if we already know that
1565 : // the index is within the bounds of [0.0, length[.
1566 4714 : DeferReplacement(node, node->InputAt(0));
1567 : } else {
1568 : NodeProperties::ChangeOp(
1569 86632 : node, simplified()->CheckedUint32Bounds(p.feedback()));
1570 : }
1571 : }
1572 : } else {
1573 : VisitBinop(
1574 : node,
1575 : UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, p.feedback()),
1576 13949 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1577 13949 : if (lower()) {
1578 : NodeProperties::ChangeOp(
1579 5542 : node, simplified()->CheckedUint32Bounds(p.feedback()));
1580 : }
1581 : }
1582 : } else {
1583 : DCHECK(length_type.Is(type_cache_->kPositiveSafeInteger));
1584 : VisitBinop(node,
1585 : UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, p.feedback()),
1586 590 : UseInfo::Word64(), MachineRepresentation::kWord64);
1587 590 : if (lower()) {
1588 : NodeProperties::ChangeOp(
1589 384 : node, simplified()->CheckedUint64Bounds(p.feedback()));
1590 : }
1591 : }
1592 175392 : }
1593 :
1594 : // Dispatching routine for visiting the node {node} with the usage {use}.
1595 : // Depending on the operator, propagate new usage info to the inputs.
1596 178112900 : void VisitNode(Node* node, Truncation truncation,
1597 101584177 : SimplifiedLowering* lowering) {
1598 : // Unconditionally eliminate unused pure nodes (only relevant if there's
1599 : // a pure operation in between two effectful ones, where the last one
1600 : // is unused).
1601 : // Note: We must not do this for constants, as they are cached and we
1602 : // would thus kill the cached {node} during lowering (i.e. replace all
1603 : // uses with Dead), but at that point some node lowering might have
1604 : // already taken the constant {node} from the cache (while it was in
1605 : // a sane state still) and we would afterwards replace that use with
1606 : // Dead as well.
1607 230648546 : if (node->op()->ValueInputCount() > 0 &&
1608 122353349 : node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) {
1609 99872 : return VisitUnused(node);
1610 : }
1611 :
1612 88826948 : if (lower()) InsertUnreachableIfNecessary(node);
1613 :
1614 88836103 : switch (node->opcode()) {
1615 : //------------------------------------------------------------------
1616 : // Common operators.
1617 : //------------------------------------------------------------------
1618 : case IrOpcode::kStart:
1619 : // We use Start as a terminator for the frame state chain, so even
1620 : // tho Start doesn't really produce a value, we have to say Tagged
1621 : // here, otherwise the input conversion will fail.
1622 : return VisitLeaf(node, MachineRepresentation::kTagged);
1623 : case IrOpcode::kParameter:
1624 : // TODO(titzer): use representation from linkage.
1625 5936751 : return VisitUnop(node, UseInfo::None(), MachineRepresentation::kTagged);
1626 : case IrOpcode::kInt32Constant:
1627 : return VisitLeaf(node, MachineRepresentation::kWord32);
1628 : case IrOpcode::kInt64Constant:
1629 : return VisitLeaf(node, MachineRepresentation::kWord64);
1630 : case IrOpcode::kExternalConstant:
1631 : return VisitLeaf(node, MachineType::PointerRepresentation());
1632 : case IrOpcode::kNumberConstant: {
1633 3921703 : double const value = OpParameter<double>(node->op());
1634 : int value_as_int;
1635 3921703 : if (DoubleToSmiInteger(value, &value_as_int)) {
1636 : VisitLeaf(node, MachineRepresentation::kTaggedSigned);
1637 3753589 : if (lower()) {
1638 1206735 : intptr_t smi = bit_cast<intptr_t>(Smi::FromInt(value_as_int));
1639 1206735 : DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(smi));
1640 : }
1641 : return;
1642 : }
1643 : VisitLeaf(node, MachineRepresentation::kTagged);
1644 : return;
1645 : }
1646 : case IrOpcode::kHeapConstant:
1647 : case IrOpcode::kDelayedStringConstant:
1648 : return VisitLeaf(node, MachineRepresentation::kTaggedPointer);
1649 : case IrOpcode::kPointerConstant: {
1650 : VisitLeaf(node, MachineType::PointerRepresentation());
1651 618 : if (lower()) {
1652 206 : intptr_t const value = OpParameter<intptr_t>(node->op());
1653 206 : DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
1654 : }
1655 : return;
1656 : }
1657 :
1658 : case IrOpcode::kBranch: {
1659 : DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
1660 1788891 : ProcessInput(node, 0, UseInfo::Bool());
1661 1788846 : EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1662 1788846 : return;
1663 : }
1664 : case IrOpcode::kSwitch:
1665 19149 : ProcessInput(node, 0, UseInfo::TruncatingWord32());
1666 19149 : EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1667 19149 : return;
1668 : case IrOpcode::kSelect:
1669 42677 : return VisitSelect(node, truncation, lowering);
1670 : case IrOpcode::kPhi:
1671 1531306 : return VisitPhi(node, truncation, lowering);
1672 : case IrOpcode::kCall:
1673 872892 : return VisitCall(node, lowering);
1674 :
1675 : //------------------------------------------------------------------
1676 : // JavaScript operators.
1677 : //------------------------------------------------------------------
1678 : case IrOpcode::kToBoolean: {
1679 133294 : if (truncation.IsUsedAsBool()) {
1680 132634 : ProcessInput(node, 0, UseInfo::Bool());
1681 : SetOutput(node, MachineRepresentation::kBit);
1682 174493 : if (lower()) DeferReplacement(node, node->InputAt(0));
1683 : } else {
1684 659 : VisitInputs(node);
1685 : SetOutput(node, MachineRepresentation::kTaggedPointer);
1686 : }
1687 : return;
1688 : }
1689 : case IrOpcode::kJSToNumber:
1690 : case IrOpcode::kJSToNumberConvertBigInt:
1691 : case IrOpcode::kJSToNumeric: {
1692 32757 : VisitInputs(node);
1693 : // TODO(bmeurer): Optimize somewhat based on input type?
1694 32757 : if (truncation.IsUsedAsWord32()) {
1695 : SetOutput(node, MachineRepresentation::kWord32);
1696 298 : if (lower())
1697 72 : lowering->DoJSToNumberOrNumericTruncatesToWord32(node, this);
1698 32459 : } else if (truncation.IsUsedAsFloat64()) {
1699 : SetOutput(node, MachineRepresentation::kFloat64);
1700 4977 : if (lower())
1701 1413 : lowering->DoJSToNumberOrNumericTruncatesToFloat64(node, this);
1702 : } else {
1703 : SetOutput(node, MachineRepresentation::kTagged);
1704 : }
1705 : return;
1706 : }
1707 :
1708 : //------------------------------------------------------------------
1709 : // Simplified operators.
1710 : //------------------------------------------------------------------
1711 : case IrOpcode::kBooleanNot: {
1712 9948 : if (lower()) {
1713 3209 : NodeInfo* input_info = GetInfo(node->InputAt(0));
1714 3209 : if (input_info->representation() == MachineRepresentation::kBit) {
1715 : // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
1716 1310746 : node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
1717 2350 : NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
1718 859 : } else if (CanBeTaggedPointer(input_info->representation())) {
1719 : // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
1720 1718 : node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
1721 859 : NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
1722 : } else {
1723 : DCHECK(TypeOf(node->InputAt(0)).IsNone());
1724 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1725 : }
1726 : } else {
1727 : // No input representation requirement; adapt during lowering.
1728 6739 : ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
1729 : SetOutput(node, MachineRepresentation::kBit);
1730 : }
1731 : return;
1732 : }
1733 : case IrOpcode::kNumberEqual: {
1734 153698 : Type const lhs_type = TypeOf(node->InputAt(0));
1735 153698 : Type const rhs_type = TypeOf(node->InputAt(1));
1736 : // Regular number comparisons in JavaScript generally identify zeros,
1737 : // so we always pass kIdentifyZeros for the inputs, and in addition
1738 : // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
1739 : // For equality we also handle the case that one side is non-zero, in
1740 : // which case we allow to truncate NaN to 0 on the other side.
1741 210401 : if ((lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
1742 250806 : rhs_type.Is(Type::Unsigned32OrMinusZero())) ||
1743 149 : (lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1744 36 : rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1745 36 : OneInputCannotBe(node, type_cache_->kZeroish))) {
1746 : // => unsigned Int32Cmp
1747 : VisitBinop(node, UseInfo::TruncatingWord32(),
1748 : MachineRepresentation::kBit);
1749 70272 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1750 : return;
1751 : }
1752 118833 : if ((lhs_type.Is(Type::Signed32OrMinusZero()) &&
1753 172520 : rhs_type.Is(Type::Signed32OrMinusZero())) ||
1754 65 : (lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
1755 36 : rhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
1756 36 : OneInputCannotBe(node, type_cache_->kZeroish))) {
1757 : // => signed Int32Cmp
1758 : VisitBinop(node, UseInfo::TruncatingWord32(),
1759 : MachineRepresentation::kBit);
1760 28549 : if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1761 : return;
1762 : }
1763 : // => Float64Cmp
1764 : VisitBinop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
1765 : MachineRepresentation::kBit);
1766 83610 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1767 : return;
1768 : }
1769 : case IrOpcode::kNumberLessThan:
1770 : case IrOpcode::kNumberLessThanOrEqual: {
1771 182928 : Type const lhs_type = TypeOf(node->InputAt(0));
1772 182928 : Type const rhs_type = TypeOf(node->InputAt(1));
1773 : // Regular number comparisons in JavaScript generally identify zeros,
1774 : // so we always pass kIdentifyZeros for the inputs, and in addition
1775 : // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
1776 297739 : if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
1777 : rhs_type.Is(Type::Unsigned32OrMinusZero())) {
1778 : // => unsigned Int32Cmp
1779 : VisitBinop(node, UseInfo::TruncatingWord32(),
1780 : MachineRepresentation::kBit);
1781 129151 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1782 96089 : } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
1783 : rhs_type.Is(Type::Signed32OrMinusZero())) {
1784 : // => signed Int32Cmp
1785 : VisitBinop(node, UseInfo::TruncatingWord32(),
1786 : MachineRepresentation::kBit);
1787 17583 : if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1788 : } else {
1789 : // => Float64Cmp
1790 : VisitBinop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
1791 : MachineRepresentation::kBit);
1792 68052 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1793 : }
1794 : return;
1795 : }
1796 :
1797 : case IrOpcode::kSpeculativeSafeIntegerAdd:
1798 : case IrOpcode::kSpeculativeSafeIntegerSubtract:
1799 803721 : return VisitSpeculativeIntegerAdditiveOp(node, truncation, lowering);
1800 :
1801 : case IrOpcode::kSpeculativeNumberAdd:
1802 : case IrOpcode::kSpeculativeNumberSubtract:
1803 4014 : return VisitSpeculativeAdditiveOp(node, truncation, lowering);
1804 :
1805 : case IrOpcode::kSpeculativeNumberLessThan:
1806 : case IrOpcode::kSpeculativeNumberLessThanOrEqual:
1807 : case IrOpcode::kSpeculativeNumberEqual: {
1808 397481 : Type const lhs_type = TypeOf(node->InputAt(0));
1809 397481 : Type const rhs_type = TypeOf(node->InputAt(1));
1810 : // Regular number comparisons in JavaScript generally identify zeros,
1811 : // so we always pass kIdentifyZeros for the inputs, and in addition
1812 : // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
1813 671168 : if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
1814 : rhs_type.Is(Type::Unsigned32OrMinusZero())) {
1815 : // => unsigned Int32Cmp
1816 : VisitBinop(node, UseInfo::TruncatingWord32(),
1817 : MachineRepresentation::kBit);
1818 6477 : if (lower()) ChangeToPureOp(node, Uint32Op(node));
1819 : return;
1820 675944 : } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
1821 : rhs_type.Is(Type::Signed32OrMinusZero())) {
1822 : // => signed Int32Cmp
1823 : VisitBinop(node, UseInfo::TruncatingWord32(),
1824 : MachineRepresentation::kBit);
1825 248398 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1826 : return;
1827 : }
1828 : // Try to use type feedback.
1829 206512 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1830 206510 : switch (hint) {
1831 : case NumberOperationHint::kSigned32:
1832 : case NumberOperationHint::kSignedSmall:
1833 164426 : if (propagate()) {
1834 : VisitBinop(node,
1835 : CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
1836 : kIdentifyZeros),
1837 237036 : MachineRepresentation::kBit);
1838 45905 : } else if (retype()) {
1839 : SetOutput(node, MachineRepresentation::kBit, Type::Any());
1840 : } else {
1841 : DCHECK(lower());
1842 : Node* lhs = node->InputAt(0);
1843 : Node* rhs = node->InputAt(1);
1844 33569 : if (IsNodeRepresentationTagged(lhs) &&
1845 : IsNodeRepresentationTagged(rhs)) {
1846 : VisitBinop(node,
1847 : UseInfo::CheckedSignedSmallAsTaggedSigned(
1848 : VectorSlotPair(), kIdentifyZeros),
1849 30414 : MachineRepresentation::kBit);
1850 : ChangeToPureOp(
1851 15207 : node, changer_->TaggedSignedOperatorFor(node->opcode()));
1852 :
1853 : } else {
1854 : VisitBinop(node,
1855 : CheckedUseInfoAsWord32FromHint(
1856 : hint, VectorSlotPair(), kIdentifyZeros),
1857 5336 : MachineRepresentation::kBit);
1858 2668 : ChangeToPureOp(node, Int32Op(node));
1859 : }
1860 : }
1861 : return;
1862 : case NumberOperationHint::kSignedSmallInputs:
1863 : // This doesn't make sense for compare operations.
1864 0 : UNREACHABLE();
1865 : case NumberOperationHint::kNumberOrOddball:
1866 : // Abstract and strict equality don't perform ToNumber conversions
1867 : // on Oddballs, so make sure we don't accidentially sneak in a
1868 : // hint with Oddball feedback here.
1869 : DCHECK_NE(IrOpcode::kSpeculativeNumberEqual, node->opcode());
1870 : V8_FALLTHROUGH;
1871 : case NumberOperationHint::kNumber:
1872 : VisitBinop(node,
1873 : CheckedUseInfoAsFloat64FromHint(hint, VectorSlotPair(),
1874 : kIdentifyZeros),
1875 84168 : MachineRepresentation::kBit);
1876 51991 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1877 : return;
1878 : }
1879 0 : UNREACHABLE();
1880 : return;
1881 : }
1882 :
1883 : case IrOpcode::kNumberAdd:
1884 : case IrOpcode::kNumberSubtract: {
1885 758517 : if (TypeOf(node->InputAt(0))
1886 2794200 : .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1887 : TypeOf(node->InputAt(1))
1888 2457672 : .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1889 1455459 : (TypeOf(node).Is(Type::Signed32()) ||
1890 536042 : TypeOf(node).Is(Type::Unsigned32()) ||
1891 : truncation.IsUsedAsWord32())) {
1892 : // => Int32Add/Sub
1893 162739 : VisitWord32TruncatingBinop(node);
1894 198697 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1895 2375303 : } else if (jsgraph_->machine()->Is64() &&
1896 603552 : BothInputsAre(node, type_cache_->kSafeInteger) &&
1897 611315 : GetUpperBound(node).Is(type_cache_->kSafeInteger)) {
1898 : // => Int64Add/Sub
1899 7749 : VisitInt64Binop(node);
1900 10284 : if (lower()) ChangeToPureOp(node, Int64Op(node));
1901 : } else {
1902 : // => Float64Add/Sub
1903 588018 : VisitFloat64Binop(node);
1904 663040 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1905 : }
1906 : return;
1907 : }
1908 : case IrOpcode::kSpeculativeNumberMultiply: {
1909 123018 : if (BothInputsAre(node, Type::Integral32()) &&
1910 52941 : (NodeProperties::GetType(node).Is(Type::Signed32()) ||
1911 47408 : NodeProperties::GetType(node).Is(Type::Unsigned32()) ||
1912 339 : (truncation.IsUsedAsWord32() &&
1913 : NodeProperties::GetType(node).Is(
1914 41345 : type_cache_->kSafeIntegerOrMinusZero)))) {
1915 : // Multiply reduces to Int32Mul if the inputs are integers, and
1916 : // (a) the output is either known to be Signed32, or
1917 : // (b) the output is known to be Unsigned32, or
1918 : // (c) the uses are truncating and the result is in the safe
1919 : // integer range.
1920 1421 : VisitWord32TruncatingBinop(node);
1921 1788 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1922 : return;
1923 : }
1924 : // Try to use type feedback.
1925 39585 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1926 39585 : Type input0_type = TypeOf(node->InputAt(0));
1927 39585 : Type input1_type = TypeOf(node->InputAt(1));
1928 :
1929 : // Handle the case when no int32 checks on inputs are necessary
1930 : // (but an overflow check is needed on the output).
1931 39585 : if (BothInputsAre(node, Type::Signed32())) {
1932 : // If both inputs and feedback are int32, use the overflow op.
1933 5892 : if (hint == NumberOperationHint::kSignedSmall ||
1934 2946 : hint == NumberOperationHint::kSigned32) {
1935 : VisitBinop(node, UseInfo::TruncatingWord32(),
1936 : MachineRepresentation::kWord32, Type::Signed32());
1937 2946 : if (lower()) {
1938 : LowerToCheckedInt32Mul(node, truncation, input0_type,
1939 944 : input1_type);
1940 : }
1941 : return;
1942 : }
1943 : }
1944 :
1945 73278 : if (hint == NumberOperationHint::kSignedSmall ||
1946 36639 : hint == NumberOperationHint::kSigned32) {
1947 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1948 33418 : MachineRepresentation::kWord32, Type::Signed32());
1949 16709 : if (lower()) {
1950 5031 : LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type);
1951 : }
1952 : return;
1953 : }
1954 :
1955 : // Checked float64 x float64 => float64
1956 : VisitBinop(node,
1957 : UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1958 : VectorSlotPair()),
1959 39860 : MachineRepresentation::kFloat64, Type::Number());
1960 25574 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1961 : return;
1962 : }
1963 : case IrOpcode::kNumberMultiply: {
1964 68292 : if (TypeOf(node->InputAt(0)).Is(Type::Integral32()) &&
1965 74417 : TypeOf(node->InputAt(1)).Is(Type::Integral32()) &&
1966 39876 : (TypeOf(node).Is(Type::Signed32()) ||
1967 38165 : TypeOf(node).Is(Type::Unsigned32()) ||
1968 899 : (truncation.IsUsedAsWord32() &&
1969 31114 : TypeOf(node).Is(type_cache_->kSafeIntegerOrMinusZero)))) {
1970 : // Multiply reduces to Int32Mul if the inputs are integers, and
1971 : // (a) the output is either known to be Signed32, or
1972 : // (b) the output is known to be Unsigned32, or
1973 : // (c) the uses are truncating and the result is in the safe
1974 : // integer range.
1975 2277 : VisitWord32TruncatingBinop(node);
1976 2746 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1977 : return;
1978 : }
1979 : // Number x Number => Float64Mul
1980 27039 : VisitFloat64Binop(node);
1981 34722 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1982 : return;
1983 : }
1984 : case IrOpcode::kSpeculativeNumberDivide: {
1985 57264 : if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
1986 : // => unsigned Uint32Div
1987 563 : VisitWord32TruncatingBinop(node);
1988 563 : if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
1989 : return;
1990 : }
1991 49955 : if (BothInputsAreSigned32(node)) {
1992 28572 : if (NodeProperties::GetType(node).Is(Type::Signed32())) {
1993 : // => signed Int32Div
1994 0 : VisitWord32TruncatingBinop(node);
1995 0 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1996 : return;
1997 : }
1998 14286 : if (truncation.IsUsedAsWord32()) {
1999 : // => signed Int32Div
2000 6049 : VisitWord32TruncatingBinop(node);
2001 6049 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2002 : return;
2003 : }
2004 : }
2005 :
2006 : // Try to use type feedback.
2007 43906 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2008 :
2009 : // Handle the case when no uint32 checks on inputs are necessary
2010 : // (but an overflow check is needed on the output).
2011 43906 : if (BothInputsAreUnsigned32(node)) {
2012 12366 : if (hint == NumberOperationHint::kSignedSmall ||
2013 6183 : hint == NumberOperationHint::kSigned32) {
2014 : VisitBinop(node, UseInfo::TruncatingWord32(),
2015 : MachineRepresentation::kWord32, Type::Unsigned32());
2016 259 : if (lower()) ChangeToUint32OverflowOp(node);
2017 : return;
2018 : }
2019 : }
2020 :
2021 : // Handle the case when no int32 checks on inputs are necessary
2022 : // (but an overflow check is needed on the output).
2023 43647 : if (BothInputsAreSigned32(node)) {
2024 : // If both the inputs the feedback are int32, use the overflow op.
2025 15986 : if (hint == NumberOperationHint::kSignedSmall ||
2026 7993 : hint == NumberOperationHint::kSigned32) {
2027 : VisitBinop(node, UseInfo::TruncatingWord32(),
2028 : MachineRepresentation::kWord32, Type::Signed32());
2029 15 : if (lower()) ChangeToInt32OverflowOp(node);
2030 : return;
2031 : }
2032 : }
2033 :
2034 87264 : if (hint == NumberOperationHint::kSigned32 ||
2035 86334 : hint == NumberOperationHint::kSignedSmall ||
2036 : hint == NumberOperationHint::kSignedSmallInputs) {
2037 : // If the result is truncated, we only need to check the inputs.
2038 37290 : if (truncation.IsUsedAsWord32()) {
2039 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2040 4808 : MachineRepresentation::kWord32);
2041 2404 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2042 : return;
2043 34886 : } else if (hint != NumberOperationHint::kSignedSmallInputs) {
2044 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2045 1642 : MachineRepresentation::kWord32, Type::Signed32());
2046 821 : if (lower()) ChangeToInt32OverflowOp(node);
2047 : return;
2048 : }
2049 : }
2050 :
2051 : // default case => Float64Div
2052 : VisitBinop(node,
2053 : UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
2054 : VectorSlotPair()),
2055 80814 : MachineRepresentation::kFloat64, Type::Number());
2056 52111 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2057 : return;
2058 : }
2059 : case IrOpcode::kNumberDivide: {
2060 49532 : if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
2061 50648 : TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
2062 905 : (truncation.IsUsedAsWord32() ||
2063 20504 : TypeOf(node).Is(Type::Unsigned32()))) {
2064 : // => unsigned Uint32Div
2065 211 : VisitWord32TruncatingBinop(node);
2066 211 : if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
2067 : return;
2068 : }
2069 50168 : if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
2070 52812 : TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
2071 2382 : (truncation.IsUsedAsWord32() ||
2072 21770 : TypeOf(node).Is(Type::Signed32()))) {
2073 : // => signed Int32Div
2074 262 : VisitWord32TruncatingBinop(node);
2075 262 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2076 : return;
2077 : }
2078 : // Number x Number => Float64Div
2079 19126 : VisitFloat64Binop(node);
2080 23933 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2081 : return;
2082 : }
2083 : case IrOpcode::kSpeculativeNumberModulus:
2084 12594 : return VisitSpeculativeNumberModulus(node, truncation, lowering);
2085 : case IrOpcode::kNumberModulus: {
2086 6688 : Type const lhs_type = TypeOf(node->InputAt(0));
2087 6688 : Type const rhs_type = TypeOf(node->InputAt(1));
2088 14201 : if ((lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2089 7130 : rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) &&
2090 221 : (truncation.IsUsedAsWord32() ||
2091 7130 : TypeOf(node).Is(Type::Unsigned32()))) {
2092 : // => unsigned Uint32Mod
2093 388 : VisitWord32TruncatingBinop(node);
2094 388 : if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
2095 : return;
2096 : }
2097 14156 : if ((lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2098 7411 : rhs_type.Is(Type::Signed32OrMinusZeroOrNaN())) &&
2099 8628 : (truncation.IsUsedAsWord32() || TypeOf(node).Is(Type::Signed32()) ||
2100 78 : (truncation.IdentifiesZeroAndMinusZero() &&
2101 6378 : TypeOf(node).Is(Type::Signed32OrMinusZero())))) {
2102 : // => signed Int32Mod
2103 412 : VisitWord32TruncatingBinop(node);
2104 412 : if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
2105 : return;
2106 : }
2107 : // => Float64Mod
2108 : // For the left hand side we just propagate the identify zeros
2109 : // mode of the {truncation}; and for modulus the sign of the
2110 : // right hand side doesn't matter anyways, so in particular there's
2111 : // no observable difference between a 0 and a -0 then.
2112 : UseInfo const lhs_use =
2113 : UseInfo::TruncatingFloat64(truncation.identify_zeros());
2114 : UseInfo const rhs_use = UseInfo::TruncatingFloat64(kIdentifyZeros);
2115 5888 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64);
2116 7510 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2117 : return;
2118 : }
2119 : case IrOpcode::kNumberBitwiseOr:
2120 : case IrOpcode::kNumberBitwiseXor:
2121 : case IrOpcode::kNumberBitwiseAnd: {
2122 23882 : VisitWord32TruncatingBinop(node);
2123 31727 : if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
2124 : return;
2125 : }
2126 : case IrOpcode::kSpeculativeNumberBitwiseOr:
2127 : case IrOpcode::kSpeculativeNumberBitwiseXor:
2128 : case IrOpcode::kSpeculativeNumberBitwiseAnd:
2129 85638 : VisitSpeculativeInt32Binop(node);
2130 85636 : if (lower()) {
2131 22658 : ChangeToPureOp(node, Int32Op(node));
2132 : }
2133 : return;
2134 : case IrOpcode::kNumberShiftLeft: {
2135 5035 : Type rhs_type = GetUpperBound(node->InputAt(1));
2136 : VisitBinop(node, UseInfo::TruncatingWord32(),
2137 5035 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2138 5035 : if (lower()) {
2139 1623 : MaskShiftOperand(node, rhs_type);
2140 1623 : ChangeToPureOp(node, lowering->machine()->Word32Shl());
2141 : }
2142 : return;
2143 : }
2144 : case IrOpcode::kSpeculativeNumberShiftLeft: {
2145 8834 : if (BothInputsAre(node, Type::NumberOrOddball())) {
2146 8055 : Type rhs_type = GetUpperBound(node->InputAt(1));
2147 : VisitBinop(node, UseInfo::TruncatingWord32(),
2148 : UseInfo::TruncatingWord32(),
2149 8055 : MachineRepresentation::kWord32);
2150 8054 : if (lower()) {
2151 1830 : MaskShiftOperand(node, rhs_type);
2152 1830 : ChangeToPureOp(node, lowering->machine()->Word32Shl());
2153 : }
2154 : return;
2155 : }
2156 779 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2157 779 : Type rhs_type = GetUpperBound(node->InputAt(1));
2158 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2159 1558 : MachineRepresentation::kWord32, Type::Signed32());
2160 779 : if (lower()) {
2161 248 : MaskShiftOperand(node, rhs_type);
2162 248 : ChangeToPureOp(node, lowering->machine()->Word32Shl());
2163 : }
2164 : return;
2165 : }
2166 : case IrOpcode::kNumberShiftRight: {
2167 4417 : Type rhs_type = GetUpperBound(node->InputAt(1));
2168 : VisitBinop(node, UseInfo::TruncatingWord32(),
2169 4417 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2170 4417 : if (lower()) {
2171 1442 : MaskShiftOperand(node, rhs_type);
2172 1442 : ChangeToPureOp(node, lowering->machine()->Word32Sar());
2173 : }
2174 : return;
2175 : }
2176 : case IrOpcode::kSpeculativeNumberShiftRight: {
2177 24270 : if (BothInputsAre(node, Type::NumberOrOddball())) {
2178 22663 : Type rhs_type = GetUpperBound(node->InputAt(1));
2179 : VisitBinop(node, UseInfo::TruncatingWord32(),
2180 : UseInfo::TruncatingWord32(),
2181 22663 : MachineRepresentation::kWord32);
2182 22663 : if (lower()) {
2183 5028 : MaskShiftOperand(node, rhs_type);
2184 5028 : ChangeToPureOp(node, lowering->machine()->Word32Sar());
2185 : }
2186 : return;
2187 : }
2188 1607 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2189 1607 : Type rhs_type = GetUpperBound(node->InputAt(1));
2190 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2191 3214 : MachineRepresentation::kWord32, Type::Signed32());
2192 1607 : if (lower()) {
2193 475 : MaskShiftOperand(node, rhs_type);
2194 475 : ChangeToPureOp(node, lowering->machine()->Word32Sar());
2195 : }
2196 : return;
2197 : }
2198 : case IrOpcode::kNumberShiftRightLogical: {
2199 4546 : Type rhs_type = GetUpperBound(node->InputAt(1));
2200 : VisitBinop(node, UseInfo::TruncatingWord32(),
2201 4546 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2202 4546 : if (lower()) {
2203 1495 : MaskShiftOperand(node, rhs_type);
2204 1495 : ChangeToPureOp(node, lowering->machine()->Word32Shr());
2205 : }
2206 : return;
2207 : }
2208 : case IrOpcode::kSpeculativeNumberShiftRightLogical: {
2209 9204 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2210 9204 : Type rhs_type = GetUpperBound(node->InputAt(1));
2211 21662 : if (rhs_type.Is(type_cache_->kZeroish) &&
2212 6508 : (hint == NumberOperationHint::kSignedSmall ||
2213 13139 : hint == NumberOperationHint::kSigned32) &&
2214 : !truncation.IsUsedAsWord32()) {
2215 : // The SignedSmall or Signed32 feedback means that the results that we
2216 : // have seen so far were of type Unsigned31. We speculate that this
2217 : // will continue to hold. Moreover, since the RHS is 0, the result
2218 : // will just be the (converted) LHS.
2219 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2220 650 : MachineRepresentation::kWord32, Type::Unsigned31());
2221 325 : if (lower()) {
2222 92 : node->RemoveInput(1);
2223 : NodeProperties::ChangeOp(
2224 184 : node, simplified()->CheckedUint32ToInt32(VectorSlotPair()));
2225 : }
2226 : return;
2227 : }
2228 8879 : if (BothInputsAre(node, Type::NumberOrOddball())) {
2229 : VisitBinop(node, UseInfo::TruncatingWord32(),
2230 : UseInfo::TruncatingWord32(),
2231 7366 : MachineRepresentation::kWord32);
2232 7366 : if (lower()) {
2233 1891 : MaskShiftOperand(node, rhs_type);
2234 1891 : ChangeToPureOp(node, lowering->machine()->Word32Shr());
2235 : }
2236 : return;
2237 : }
2238 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2239 3026 : MachineRepresentation::kWord32, Type::Unsigned32());
2240 1513 : if (lower()) {
2241 452 : MaskShiftOperand(node, rhs_type);
2242 452 : ChangeToPureOp(node, lowering->machine()->Word32Shr());
2243 : }
2244 : return;
2245 : }
2246 : case IrOpcode::kNumberAbs: {
2247 : // NumberAbs maps both 0 and -0 to 0, so we can generally
2248 : // pass the kIdentifyZeros truncation to its input, and
2249 : // choose to ignore minus zero in all cases.
2250 900 : Type const input_type = TypeOf(node->InputAt(0));
2251 900 : if (input_type.Is(Type::Unsigned32OrMinusZero())) {
2252 : VisitUnop(node, UseInfo::TruncatingWord32(),
2253 37 : MachineRepresentation::kWord32);
2254 52 : if (lower()) DeferReplacement(node, node->InputAt(0));
2255 863 : } else if (input_type.Is(Type::Signed32OrMinusZero())) {
2256 : VisitUnop(node, UseInfo::TruncatingWord32(),
2257 208 : MachineRepresentation::kWord32);
2258 208 : if (lower()) DeferReplacement(node, lowering->Int32Abs(node));
2259 1310 : } else if (input_type.Is(type_cache_->kPositiveIntegerOrNaN)) {
2260 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2261 14 : MachineRepresentation::kFloat64);
2262 21 : if (lower()) DeferReplacement(node, node->InputAt(0));
2263 : } else {
2264 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2265 641 : MachineRepresentation::kFloat64);
2266 830 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2267 : }
2268 : return;
2269 : }
2270 : case IrOpcode::kNumberClz32: {
2271 : VisitUnop(node, UseInfo::TruncatingWord32(),
2272 99 : MachineRepresentation::kWord32);
2273 132 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
2274 : return;
2275 : }
2276 : case IrOpcode::kNumberImul: {
2277 : VisitBinop(node, UseInfo::TruncatingWord32(),
2278 2553 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2279 3404 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
2280 : return;
2281 : }
2282 : case IrOpcode::kNumberFround: {
2283 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2284 4083 : MachineRepresentation::kFloat32);
2285 5434 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2286 : return;
2287 : }
2288 : case IrOpcode::kNumberMax: {
2289 : // It is safe to use the feedback types for left and right hand side
2290 : // here, since we can only narrow those types and thus we can only
2291 : // promise a more specific truncation.
2292 : // For NumberMax we generally propagate whether the truncation
2293 : // identifies zeros to the inputs, and we choose to ignore minus
2294 : // zero in those cases.
2295 7566 : Type const lhs_type = TypeOf(node->InputAt(0));
2296 7566 : Type const rhs_type = TypeOf(node->InputAt(1));
2297 11561 : if ((lhs_type.Is(Type::Unsigned32()) &&
2298 11716 : rhs_type.Is(Type::Unsigned32())) ||
2299 633 : (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2300 87 : rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2301 : truncation.IdentifiesZeroAndMinusZero())) {
2302 3416 : VisitWord32TruncatingBinop(node);
2303 3416 : if (lower()) {
2304 : lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
2305 1084 : MachineRepresentation::kWord32);
2306 : }
2307 7947 : } else if ((lhs_type.Is(Type::Signed32()) &&
2308 5047 : rhs_type.Is(Type::Signed32())) ||
2309 598 : (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2310 87 : rhs_type.Is(Type::Signed32OrMinusZero()) &&
2311 : truncation.IdentifiesZeroAndMinusZero())) {
2312 3253 : VisitWord32TruncatingBinop(node);
2313 3253 : if (lower()) {
2314 : lowering->DoMax(node, lowering->machine()->Int32LessThan(),
2315 1059 : MachineRepresentation::kWord32);
2316 : }
2317 2691 : } else if (jsgraph_->machine()->Is64() &&
2318 1524 : lhs_type.Is(type_cache_->kSafeInteger) &&
2319 627 : rhs_type.Is(type_cache_->kSafeInteger)) {
2320 501 : VisitInt64Binop(node);
2321 501 : if (lower()) {
2322 : lowering->DoMax(node, lowering->machine()->Int64LessThan(),
2323 162 : MachineRepresentation::kWord64);
2324 : }
2325 : } else {
2326 : VisitBinop(node,
2327 : UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2328 : MachineRepresentation::kFloat64);
2329 396 : if (lower()) {
2330 : // If the right hand side is not NaN, and the left hand side
2331 : // is not NaN (or -0 if the difference between the zeros is
2332 : // observed), we can do a simple floating point comparison here.
2333 124 : if (lhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2334 : ? Type::OrderedNumber()
2335 322 : : Type::PlainNumber()) &&
2336 : rhs_type.Is(Type::OrderedNumber())) {
2337 : lowering->DoMax(node, lowering->machine()->Float64LessThan(),
2338 50 : MachineRepresentation::kFloat64);
2339 : } else {
2340 74 : NodeProperties::ChangeOp(node, Float64Op(node));
2341 : }
2342 : }
2343 : }
2344 : return;
2345 : }
2346 : case IrOpcode::kNumberMin: {
2347 : // It is safe to use the feedback types for left and right hand side
2348 : // here, since we can only narrow those types and thus we can only
2349 : // promise a more specific truncation.
2350 : // For NumberMin we generally propagate whether the truncation
2351 : // identifies zeros to the inputs, and we choose to ignore minus
2352 : // zero in those cases.
2353 10264 : Type const lhs_type = TypeOf(node->InputAt(0));
2354 10264 : Type const rhs_type = TypeOf(node->InputAt(1));
2355 19874 : if ((lhs_type.Is(Type::Unsigned32()) &&
2356 11207 : rhs_type.Is(Type::Unsigned32())) ||
2357 343 : (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2358 87 : rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2359 : truncation.IdentifiesZeroAndMinusZero())) {
2360 9321 : VisitWord32TruncatingBinop(node);
2361 9321 : if (lower()) {
2362 : lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
2363 2984 : MachineRepresentation::kWord32);
2364 : }
2365 1402 : } else if ((lhs_type.Is(Type::Signed32()) &&
2366 1596 : rhs_type.Is(Type::Signed32())) ||
2367 223 : (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2368 87 : rhs_type.Is(Type::Signed32OrMinusZero()) &&
2369 : truncation.IdentifiesZeroAndMinusZero())) {
2370 290 : VisitWord32TruncatingBinop(node);
2371 290 : if (lower()) {
2372 : lowering->DoMin(node, lowering->machine()->Int32LessThan(),
2373 86 : MachineRepresentation::kWord32);
2374 : }
2375 1959 : } else if (jsgraph_->machine()->Is64() &&
2376 846 : lhs_type.Is(type_cache_->kSafeInteger) &&
2377 193 : rhs_type.Is(type_cache_->kSafeInteger)) {
2378 40 : VisitInt64Binop(node);
2379 40 : if (lower()) {
2380 : lowering->DoMin(node, lowering->machine()->Int64LessThan(),
2381 16 : MachineRepresentation::kWord64);
2382 : }
2383 : } else {
2384 : VisitBinop(node,
2385 : UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2386 : MachineRepresentation::kFloat64);
2387 613 : if (lower()) {
2388 : // If the left hand side is not NaN, and the right hand side
2389 : // is not NaN (or -0 if the difference between the zeros is
2390 : // observed), we can do a simple floating point comparison here.
2391 286 : if (lhs_type.Is(Type::OrderedNumber()) &&
2392 : rhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2393 : ? Type::OrderedNumber()
2394 87 : : Type::PlainNumber())) {
2395 : lowering->DoMin(node,
2396 : lowering->machine()->Float64LessThanOrEqual(),
2397 46 : MachineRepresentation::kFloat64);
2398 : } else {
2399 153 : NodeProperties::ChangeOp(node, Float64Op(node));
2400 : }
2401 : }
2402 : }
2403 : return;
2404 : }
2405 : case IrOpcode::kNumberAtan2:
2406 : case IrOpcode::kNumberPow: {
2407 : VisitBinop(node, UseInfo::TruncatingFloat64(),
2408 : MachineRepresentation::kFloat64);
2409 4013 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2410 : return;
2411 : }
2412 : case IrOpcode::kNumberCeil:
2413 : case IrOpcode::kNumberFloor:
2414 : case IrOpcode::kNumberRound:
2415 : case IrOpcode::kNumberTrunc: {
2416 : // For NumberCeil, NumberFloor, NumberRound and NumberTrunc we propagate
2417 : // the zero identification part of the truncation, and we turn them into
2418 : // no-ops if we figure out (late) that their input is already an
2419 : // integer, NaN or -0.
2420 131889 : Type const input_type = TypeOf(node->InputAt(0));
2421 : VisitUnop(node, UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2422 131889 : MachineRepresentation::kFloat64);
2423 131889 : if (lower()) {
2424 86756 : if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2425 1246 : DeferReplacement(node, node->InputAt(0));
2426 42132 : } else if (node->opcode() == IrOpcode::kNumberRound) {
2427 1556 : DeferReplacement(node, lowering->Float64Round(node));
2428 : } else {
2429 40576 : NodeProperties::ChangeOp(node, Float64Op(node));
2430 : }
2431 : }
2432 : return;
2433 : }
2434 : case IrOpcode::kNumberAcos:
2435 : case IrOpcode::kNumberAcosh:
2436 : case IrOpcode::kNumberAsin:
2437 : case IrOpcode::kNumberAsinh:
2438 : case IrOpcode::kNumberAtan:
2439 : case IrOpcode::kNumberAtanh:
2440 : case IrOpcode::kNumberCos:
2441 : case IrOpcode::kNumberCosh:
2442 : case IrOpcode::kNumberExp:
2443 : case IrOpcode::kNumberExpm1:
2444 : case IrOpcode::kNumberLog:
2445 : case IrOpcode::kNumberLog1p:
2446 : case IrOpcode::kNumberLog2:
2447 : case IrOpcode::kNumberLog10:
2448 : case IrOpcode::kNumberCbrt:
2449 : case IrOpcode::kNumberSin:
2450 : case IrOpcode::kNumberSinh:
2451 : case IrOpcode::kNumberTan:
2452 : case IrOpcode::kNumberTanh: {
2453 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2454 961 : MachineRepresentation::kFloat64);
2455 1274 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2456 : return;
2457 : }
2458 : case IrOpcode::kNumberSign: {
2459 111 : if (InputIs(node, Type::Signed32())) {
2460 : VisitUnop(node, UseInfo::TruncatingWord32(),
2461 21 : MachineRepresentation::kWord32);
2462 21 : if (lower()) DeferReplacement(node, lowering->Int32Sign(node));
2463 : } else {
2464 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2465 90 : MachineRepresentation::kFloat64);
2466 90 : if (lower()) DeferReplacement(node, lowering->Float64Sign(node));
2467 : }
2468 : return;
2469 : }
2470 : case IrOpcode::kNumberSilenceNaN: {
2471 2402 : Type const input_type = TypeOf(node->InputAt(0));
2472 2402 : if (input_type.Is(Type::OrderedNumber())) {
2473 : // No need to silence anything if the input cannot be NaN.
2474 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2475 18 : MachineRepresentation::kFloat64);
2476 27 : if (lower()) DeferReplacement(node, node->InputAt(0));
2477 : } else {
2478 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2479 2384 : MachineRepresentation::kFloat64);
2480 3155 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2481 : }
2482 : return;
2483 : }
2484 : case IrOpcode::kNumberSqrt: {
2485 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2486 190 : MachineRepresentation::kFloat64);
2487 252 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2488 : return;
2489 : }
2490 : case IrOpcode::kNumberToBoolean: {
2491 : // For NumberToBoolean we don't care whether the input is 0 or
2492 : // -0, since both of them are mapped to false anyways, so we
2493 : // can generally pass kIdentifyZeros truncation.
2494 567 : Type const input_type = TypeOf(node->InputAt(0));
2495 567 : if (input_type.Is(Type::Integral32OrMinusZeroOrNaN())) {
2496 : // 0, -0 and NaN all map to false, so we can safely truncate
2497 : // all of them to zero here.
2498 : VisitUnop(node, UseInfo::TruncatingWord32(),
2499 309 : MachineRepresentation::kBit);
2500 309 : if (lower()) lowering->DoIntegral32ToBit(node);
2501 258 : } else if (input_type.Is(Type::OrderedNumber())) {
2502 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2503 77 : MachineRepresentation::kBit);
2504 77 : if (lower()) lowering->DoOrderedNumberToBit(node);
2505 : } else {
2506 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2507 181 : MachineRepresentation::kBit);
2508 181 : if (lower()) lowering->DoNumberToBit(node);
2509 : }
2510 : return;
2511 : }
2512 : case IrOpcode::kNumberToInt32: {
2513 : // Just change representation if necessary.
2514 : VisitUnop(node, UseInfo::TruncatingWord32(),
2515 16847 : MachineRepresentation::kWord32);
2516 22206 : if (lower()) DeferReplacement(node, node->InputAt(0));
2517 : return;
2518 : }
2519 : case IrOpcode::kNumberToString: {
2520 : VisitUnop(node, UseInfo::AnyTagged(),
2521 11449 : MachineRepresentation::kTaggedPointer);
2522 11449 : return;
2523 : }
2524 : case IrOpcode::kNumberToUint32: {
2525 : // Just change representation if necessary.
2526 : VisitUnop(node, UseInfo::TruncatingWord32(),
2527 17961 : MachineRepresentation::kWord32);
2528 23820 : if (lower()) DeferReplacement(node, node->InputAt(0));
2529 : return;
2530 : }
2531 : case IrOpcode::kNumberToUint8Clamped: {
2532 1446 : Type const input_type = TypeOf(node->InputAt(0));
2533 2892 : if (input_type.Is(type_cache_->kUint8OrMinusZeroOrNaN)) {
2534 : VisitUnop(node, UseInfo::TruncatingWord32(),
2535 45 : MachineRepresentation::kWord32);
2536 60 : if (lower()) DeferReplacement(node, node->InputAt(0));
2537 1401 : } else if (input_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) {
2538 : VisitUnop(node, UseInfo::TruncatingWord32(),
2539 240 : MachineRepresentation::kWord32);
2540 240 : if (lower()) lowering->DoUnsigned32ToUint8Clamped(node);
2541 1161 : } else if (input_type.Is(Type::Signed32OrMinusZeroOrNaN())) {
2542 : VisitUnop(node, UseInfo::TruncatingWord32(),
2543 216 : MachineRepresentation::kWord32);
2544 216 : if (lower()) lowering->DoSigned32ToUint8Clamped(node);
2545 1890 : } else if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2546 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2547 63 : MachineRepresentation::kFloat64);
2548 63 : if (lower()) lowering->DoIntegerToUint8Clamped(node);
2549 : } else {
2550 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2551 882 : MachineRepresentation::kFloat64);
2552 882 : if (lower()) lowering->DoNumberToUint8Clamped(node);
2553 : }
2554 : return;
2555 : }
2556 : case IrOpcode::kReferenceEqual: {
2557 : VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2558 575366 : if (lower()) {
2559 189550 : NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
2560 : }
2561 : return;
2562 : }
2563 : case IrOpcode::kSameValue: {
2564 36 : if (truncation.IsUnused()) return VisitUnused(node);
2565 : VisitBinop(node, UseInfo::AnyTagged(),
2566 : MachineRepresentation::kTaggedPointer);
2567 : return;
2568 : }
2569 : case IrOpcode::kTypeOf: {
2570 : return VisitUnop(node, UseInfo::AnyTagged(),
2571 59735 : MachineRepresentation::kTaggedPointer);
2572 : }
2573 : case IrOpcode::kNewConsString: {
2574 10290 : ProcessInput(node, 0, UseInfo::TruncatingWord32()); // length
2575 10290 : ProcessInput(node, 1, UseInfo::AnyTagged()); // first
2576 10290 : ProcessInput(node, 2, UseInfo::AnyTagged()); // second
2577 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2578 : return;
2579 : }
2580 : case IrOpcode::kStringConcat: {
2581 : // TODO(turbofan): We currently depend on having this first length input
2582 : // to make sure that the overflow check is properly scheduled before the
2583 : // actual string concatenation. We should also use the length to pass it
2584 : // to the builtin or decide in optimized code how to construct the
2585 : // resulting string (i.e. cons string or sequential string).
2586 60903 : ProcessInput(node, 0, UseInfo::TaggedSigned()); // length
2587 60903 : ProcessInput(node, 1, UseInfo::AnyTagged()); // first
2588 60903 : ProcessInput(node, 2, UseInfo::AnyTagged()); // second
2589 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2590 : return;
2591 : }
2592 : case IrOpcode::kStringEqual:
2593 : case IrOpcode::kStringLessThan:
2594 : case IrOpcode::kStringLessThanOrEqual: {
2595 : return VisitBinop(node, UseInfo::AnyTagged(),
2596 : MachineRepresentation::kTaggedPointer);
2597 : }
2598 : case IrOpcode::kStringCharCodeAt: {
2599 : return VisitBinop(node, UseInfo::AnyTagged(), UseInfo::Word(),
2600 8855 : MachineRepresentation::kWord32);
2601 : }
2602 : case IrOpcode::kStringCodePointAt: {
2603 : return VisitBinop(node, UseInfo::AnyTagged(), UseInfo::Word(),
2604 835 : MachineRepresentation::kTaggedSigned);
2605 : }
2606 : case IrOpcode::kStringFromSingleCharCode: {
2607 : VisitUnop(node, UseInfo::TruncatingWord32(),
2608 3569 : MachineRepresentation::kTaggedPointer);
2609 3569 : return;
2610 : }
2611 : case IrOpcode::kStringFromSingleCodePoint: {
2612 : VisitUnop(node, UseInfo::TruncatingWord32(),
2613 800 : MachineRepresentation::kTaggedPointer);
2614 800 : return;
2615 : }
2616 : case IrOpcode::kStringIndexOf: {
2617 936 : ProcessInput(node, 0, UseInfo::AnyTagged());
2618 936 : ProcessInput(node, 1, UseInfo::AnyTagged());
2619 936 : ProcessInput(node, 2, UseInfo::TaggedSigned());
2620 : SetOutput(node, MachineRepresentation::kTaggedSigned);
2621 : return;
2622 : }
2623 : case IrOpcode::kStringLength: {
2624 : // TODO(bmeurer): The input representation should be TaggedPointer.
2625 : // Fix this once we have a dedicated StringConcat/JSStringAdd
2626 : // operator, which marks it's output as TaggedPointer properly.
2627 65735 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kWord32);
2628 65735 : return;
2629 : }
2630 : case IrOpcode::kStringSubstring: {
2631 4072 : ProcessInput(node, 0, UseInfo::AnyTagged());
2632 4072 : ProcessInput(node, 1, UseInfo::TruncatingWord32());
2633 4072 : ProcessInput(node, 2, UseInfo::TruncatingWord32());
2634 4072 : ProcessRemainingInputs(node, 3);
2635 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2636 : return;
2637 : }
2638 : case IrOpcode::kStringToLowerCaseIntl:
2639 : case IrOpcode::kStringToUpperCaseIntl: {
2640 : VisitUnop(node, UseInfo::AnyTagged(),
2641 376 : MachineRepresentation::kTaggedPointer);
2642 376 : return;
2643 : }
2644 : case IrOpcode::kCheckBounds:
2645 175392 : return VisitCheckBounds(node, lowering);
2646 : case IrOpcode::kPoisonIndex: {
2647 : VisitUnop(node, UseInfo::TruncatingWord32(),
2648 4372 : MachineRepresentation::kWord32);
2649 4372 : return;
2650 : }
2651 : case IrOpcode::kCheckHeapObject: {
2652 94674 : if (InputCannotBe(node, Type::SignedSmall())) {
2653 : VisitUnop(node, UseInfo::AnyTagged(),
2654 0 : MachineRepresentation::kTaggedPointer);
2655 : } else {
2656 : VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
2657 94673 : MachineRepresentation::kTaggedPointer);
2658 : }
2659 124518 : if (lower()) DeferReplacement(node, node->InputAt(0));
2660 : return;
2661 : }
2662 : case IrOpcode::kCheckIf: {
2663 47019 : ProcessInput(node, 0, UseInfo::Bool());
2664 47019 : ProcessRemainingInputs(node, 1);
2665 : SetOutput(node, MachineRepresentation::kNone);
2666 : return;
2667 : }
2668 : case IrOpcode::kCheckInternalizedString: {
2669 5655 : VisitCheck(node, Type::InternalizedString(), lowering);
2670 5655 : return;
2671 : }
2672 : case IrOpcode::kCheckNumber: {
2673 1695 : Type const input_type = TypeOf(node->InputAt(0));
2674 1695 : if (input_type.Is(Type::Number())) {
2675 40 : VisitNoop(node, truncation);
2676 : } else {
2677 1655 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2678 : }
2679 : return;
2680 : }
2681 : case IrOpcode::kCheckReceiver: {
2682 3273 : VisitCheck(node, Type::Receiver(), lowering);
2683 3273 : return;
2684 : }
2685 : case IrOpcode::kCheckReceiverOrNullOrUndefined: {
2686 277 : VisitCheck(node, Type::ReceiverOrNullOrUndefined(), lowering);
2687 277 : return;
2688 : }
2689 : case IrOpcode::kCheckSmi: {
2690 103868 : const CheckParameters& params = CheckParametersOf(node->op());
2691 103868 : if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
2692 : VisitUnop(node,
2693 : UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros,
2694 : params.feedback()),
2695 24587 : MachineRepresentation::kWord32);
2696 : } else {
2697 : VisitUnop(
2698 : node,
2699 : UseInfo::CheckedSignedSmallAsTaggedSigned(params.feedback()),
2700 79281 : MachineRepresentation::kTaggedSigned);
2701 : }
2702 135522 : if (lower()) DeferReplacement(node, node->InputAt(0));
2703 : return;
2704 : }
2705 : case IrOpcode::kCheckString: {
2706 21635 : VisitCheck(node, Type::String(), lowering);
2707 21635 : return;
2708 : }
2709 : case IrOpcode::kCheckSymbol: {
2710 121 : VisitCheck(node, Type::Symbol(), lowering);
2711 121 : return;
2712 : }
2713 :
2714 : case IrOpcode::kAllocate: {
2715 336373 : ProcessInput(node, 0, UseInfo::Word());
2716 336373 : ProcessRemainingInputs(node, 1);
2717 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2718 : return;
2719 : }
2720 : case IrOpcode::kLoadFieldByIndex: {
2721 3906 : if (truncation.IsUnused()) return VisitUnused(node);
2722 : VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
2723 3832 : MachineRepresentation::kTagged);
2724 3832 : return;
2725 : }
2726 : case IrOpcode::kLoadField: {
2727 2429934 : if (truncation.IsUnused()) return VisitUnused(node);
2728 2241742 : FieldAccess access = FieldAccessOf(node->op());
2729 : MachineRepresentation const representation =
2730 2241746 : access.machine_type.representation();
2731 2241746 : VisitUnop(node, UseInfoForBasePointer(access), representation);
2732 2241743 : return;
2733 : }
2734 : case IrOpcode::kStoreField: {
2735 4121258 : FieldAccess access = FieldAccessOf(node->op());
2736 : Node* value_node = node->InputAt(1);
2737 4121257 : NodeInfo* input_info = GetInfo(value_node);
2738 : MachineRepresentation field_representation =
2739 4121258 : access.machine_type.representation();
2740 :
2741 : // Convert to Smi if possible, such that we can avoid a write barrier.
2742 12363771 : if (field_representation == MachineRepresentation::kTagged &&
2743 9964452 : TypeOf(value_node).Is(Type::SignedSmall())) {
2744 : field_representation = MachineRepresentation::kTaggedSigned;
2745 : }
2746 : WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2747 : access.base_is_tagged, field_representation, access.offset,
2748 4121257 : access.type, input_info->representation(), value_node);
2749 :
2750 4121257 : ProcessInput(node, 0, UseInfoForBasePointer(access));
2751 : ProcessInput(node, 1,
2752 4121260 : TruncatingUseInfoFromRepresentation(field_representation));
2753 4121260 : ProcessRemainingInputs(node, 2);
2754 : SetOutput(node, MachineRepresentation::kNone);
2755 4121260 : if (lower()) {
2756 1370089 : if (write_barrier_kind < access.write_barrier_kind) {
2757 685499 : access.write_barrier_kind = write_barrier_kind;
2758 : NodeProperties::ChangeOp(
2759 1370998 : node, jsgraph_->simplified()->StoreField(access));
2760 : }
2761 : }
2762 : return;
2763 : }
2764 : case IrOpcode::kLoadElement: {
2765 71333 : if (truncation.IsUnused()) return VisitUnused(node);
2766 68971 : ElementAccess access = ElementAccessOf(node->op());
2767 : VisitBinop(node, UseInfoForBasePointer(access), UseInfo::Word(),
2768 137944 : access.machine_type.representation());
2769 68973 : return;
2770 : }
2771 : case IrOpcode::kStoreElement: {
2772 122826 : ElementAccess access = ElementAccessOf(node->op());
2773 : Node* value_node = node->InputAt(2);
2774 122826 : NodeInfo* input_info = GetInfo(value_node);
2775 : MachineRepresentation element_representation =
2776 122826 : access.machine_type.representation();
2777 :
2778 : // Convert to Smi if possible, such that we can avoid a write barrier.
2779 368478 : if (element_representation == MachineRepresentation::kTagged &&
2780 293566 : TypeOf(value_node).Is(Type::SignedSmall())) {
2781 : element_representation = MachineRepresentation::kTaggedSigned;
2782 : }
2783 : WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2784 : access.base_is_tagged, element_representation, access.type,
2785 122826 : input_info->representation(), value_node);
2786 122826 : ProcessInput(node, 0, UseInfoForBasePointer(access)); // base
2787 122826 : ProcessInput(node, 1, UseInfo::Word()); // index
2788 : ProcessInput(node, 2,
2789 : TruncatingUseInfoFromRepresentation(
2790 122826 : element_representation)); // value
2791 122826 : ProcessRemainingInputs(node, 3);
2792 : SetOutput(node, MachineRepresentation::kNone);
2793 122826 : if (lower()) {
2794 40036 : if (write_barrier_kind < access.write_barrier_kind) {
2795 23219 : access.write_barrier_kind = write_barrier_kind;
2796 : NodeProperties::ChangeOp(
2797 46438 : node, jsgraph_->simplified()->StoreElement(access));
2798 : }
2799 : }
2800 : return;
2801 : }
2802 : case IrOpcode::kNumberIsFloat64Hole: {
2803 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2804 250 : MachineRepresentation::kBit);
2805 250 : return;
2806 : }
2807 : case IrOpcode::kTransitionAndStoreElement: {
2808 885 : Type value_type = TypeOf(node->InputAt(2));
2809 :
2810 885 : ProcessInput(node, 0, UseInfo::AnyTagged()); // array
2811 885 : ProcessInput(node, 1, UseInfo::Word()); // index
2812 :
2813 885 : if (value_type.Is(Type::SignedSmall())) {
2814 331 : ProcessInput(node, 2, UseInfo::TruncatingWord32()); // value
2815 331 : if (lower()) {
2816 : NodeProperties::ChangeOp(node,
2817 78 : simplified()->StoreSignedSmallElement());
2818 : }
2819 554 : } else if (value_type.Is(Type::Number())) {
2820 100 : ProcessInput(node, 2, UseInfo::TruncatingFloat64()); // value
2821 100 : if (lower()) {
2822 22 : Handle<Map> double_map = DoubleMapParameterOf(node->op());
2823 : NodeProperties::ChangeOp(
2824 : node,
2825 22 : simplified()->TransitionAndStoreNumberElement(double_map));
2826 : }
2827 454 : } else if (value_type.Is(Type::NonNumber())) {
2828 99 : ProcessInput(node, 2, UseInfo::AnyTagged()); // value
2829 99 : if (lower()) {
2830 21 : Handle<Map> fast_map = FastMapParameterOf(node->op());
2831 : NodeProperties::ChangeOp(
2832 : node, simplified()->TransitionAndStoreNonNumberElement(
2833 21 : fast_map, value_type));
2834 : }
2835 : } else {
2836 355 : ProcessInput(node, 2, UseInfo::AnyTagged()); // value
2837 : }
2838 :
2839 885 : ProcessRemainingInputs(node, 3);
2840 : SetOutput(node, MachineRepresentation::kNone);
2841 : return;
2842 : }
2843 : case IrOpcode::kLoadTypedElement: {
2844 : MachineRepresentation const rep =
2845 16911 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2846 16911 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2847 16911 : ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2848 16911 : ProcessInput(node, 2, UseInfo::Word()); // external pointer
2849 16911 : ProcessInput(node, 3, UseInfo::Word()); // index
2850 16911 : ProcessRemainingInputs(node, 4);
2851 : SetOutput(node, rep);
2852 : return;
2853 : }
2854 : case IrOpcode::kLoadDataViewElement: {
2855 : MachineRepresentation const rep =
2856 804 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2857 804 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2858 804 : ProcessInput(node, 1, UseInfo::Word()); // external pointer
2859 804 : ProcessInput(node, 2, UseInfo::Word()); // byte offset
2860 804 : ProcessInput(node, 3, UseInfo::Word()); // index
2861 804 : ProcessInput(node, 4, UseInfo::Bool()); // little-endian
2862 804 : ProcessRemainingInputs(node, 5);
2863 : SetOutput(node, rep);
2864 : return;
2865 : }
2866 : case IrOpcode::kStoreTypedElement: {
2867 : MachineRepresentation const rep =
2868 14924 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2869 14924 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2870 14924 : ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2871 14924 : ProcessInput(node, 2, UseInfo::Word()); // external pointer
2872 14924 : ProcessInput(node, 3, UseInfo::Word()); // index
2873 : ProcessInput(node, 4,
2874 14924 : TruncatingUseInfoFromRepresentation(rep)); // value
2875 14924 : ProcessRemainingInputs(node, 5);
2876 : SetOutput(node, MachineRepresentation::kNone);
2877 : return;
2878 : }
2879 : case IrOpcode::kStoreDataViewElement: {
2880 : MachineRepresentation const rep =
2881 591 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2882 591 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2883 591 : ProcessInput(node, 1, UseInfo::Word()); // external pointer
2884 591 : ProcessInput(node, 2, UseInfo::Word()); // byte offset
2885 591 : ProcessInput(node, 3, UseInfo::Word()); // index
2886 : ProcessInput(node, 4,
2887 591 : TruncatingUseInfoFromRepresentation(rep)); // value
2888 591 : ProcessInput(node, 5, UseInfo::Bool()); // little-endian
2889 591 : ProcessRemainingInputs(node, 6);
2890 : SetOutput(node, MachineRepresentation::kNone);
2891 : return;
2892 : }
2893 : case IrOpcode::kConvertReceiver: {
2894 2733 : Type input_type = TypeOf(node->InputAt(0));
2895 : VisitBinop(node, UseInfo::AnyTagged(),
2896 : MachineRepresentation::kTaggedPointer);
2897 2733 : if (lower()) {
2898 : // Try to optimize the {node} based on the input type.
2899 892 : if (input_type.Is(Type::Receiver())) {
2900 0 : DeferReplacement(node, node->InputAt(0));
2901 892 : } else if (input_type.Is(Type::NullOrUndefined())) {
2902 0 : DeferReplacement(node, node->InputAt(1));
2903 892 : } else if (!input_type.Maybe(Type::NullOrUndefined())) {
2904 : NodeProperties::ChangeOp(
2905 : node, lowering->simplified()->ConvertReceiver(
2906 83 : ConvertReceiverMode::kNotNullOrUndefined));
2907 : }
2908 : }
2909 : return;
2910 : }
2911 : case IrOpcode::kPlainPrimitiveToNumber: {
2912 2726 : if (InputIs(node, Type::Boolean())) {
2913 211 : VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32);
2914 274 : if (lower()) DeferReplacement(node, node->InputAt(0));
2915 2515 : } else if (InputIs(node, Type::String())) {
2916 1041 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2917 1041 : if (lower()) {
2918 344 : NodeProperties::ChangeOp(node, simplified()->StringToNumber());
2919 : }
2920 1474 : } else if (truncation.IsUsedAsWord32()) {
2921 57 : if (InputIs(node, Type::NumberOrOddball())) {
2922 : VisitUnop(node, UseInfo::TruncatingWord32(),
2923 30 : MachineRepresentation::kWord32);
2924 40 : if (lower()) DeferReplacement(node, node->InputAt(0));
2925 : } else {
2926 : VisitUnop(node, UseInfo::AnyTagged(),
2927 27 : MachineRepresentation::kWord32);
2928 27 : if (lower()) {
2929 : NodeProperties::ChangeOp(node,
2930 9 : simplified()->PlainPrimitiveToWord32());
2931 : }
2932 : }
2933 1417 : } else if (truncation.IsUsedAsFloat64()) {
2934 1328 : if (InputIs(node, Type::NumberOrOddball())) {
2935 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2936 1328 : MachineRepresentation::kFloat64);
2937 1674 : if (lower()) DeferReplacement(node, node->InputAt(0));
2938 : } else {
2939 : VisitUnop(node, UseInfo::AnyTagged(),
2940 0 : MachineRepresentation::kFloat64);
2941 0 : if (lower()) {
2942 : NodeProperties::ChangeOp(node,
2943 0 : simplified()->PlainPrimitiveToFloat64());
2944 : }
2945 : }
2946 : } else {
2947 89 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2948 : }
2949 : return;
2950 : }
2951 : case IrOpcode::kSpeculativeToNumber: {
2952 154930 : NumberOperationParameters const& p =
2953 154930 : NumberOperationParametersOf(node->op());
2954 154930 : switch (p.hint()) {
2955 : case NumberOperationHint::kSigned32:
2956 : case NumberOperationHint::kSignedSmall:
2957 : case NumberOperationHint::kSignedSmallInputs:
2958 : VisitUnop(node,
2959 6197 : CheckedUseInfoAsWord32FromHint(p.hint(), p.feedback()),
2960 6197 : MachineRepresentation::kWord32, Type::Signed32());
2961 6197 : break;
2962 : case NumberOperationHint::kNumber:
2963 : case NumberOperationHint::kNumberOrOddball:
2964 : VisitUnop(node,
2965 148733 : CheckedUseInfoAsFloat64FromHint(p.hint(), p.feedback()),
2966 148733 : MachineRepresentation::kFloat64);
2967 148733 : break;
2968 : }
2969 202281 : if (lower()) DeferReplacement(node, node->InputAt(0));
2970 : return;
2971 : }
2972 : case IrOpcode::kObjectIsArrayBufferView: {
2973 : // TODO(turbofan): Introduce a Type::ArrayBufferView?
2974 48 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2975 48 : return;
2976 : }
2977 : case IrOpcode::kObjectIsBigInt: {
2978 75 : VisitObjectIs(node, Type::BigInt(), lowering);
2979 75 : return;
2980 : }
2981 : case IrOpcode::kObjectIsCallable: {
2982 315 : VisitObjectIs(node, Type::Callable(), lowering);
2983 315 : return;
2984 : }
2985 : case IrOpcode::kObjectIsConstructor: {
2986 : // TODO(turbofan): Introduce a Type::Constructor?
2987 618 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2988 618 : return;
2989 : }
2990 : case IrOpcode::kObjectIsDetectableCallable: {
2991 41757 : VisitObjectIs(node, Type::DetectableCallable(), lowering);
2992 41759 : return;
2993 : }
2994 : case IrOpcode::kObjectIsFiniteNumber: {
2995 588 : Type const input_type = GetUpperBound(node->InputAt(0));
2996 1176 : if (input_type.Is(type_cache_->kSafeInteger)) {
2997 210 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
2998 210 : if (lower()) {
2999 70 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3000 : }
3001 378 : } else if (!input_type.Maybe(Type::Number())) {
3002 42 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3003 42 : if (lower()) {
3004 14 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3005 : }
3006 336 : } else if (input_type.Is(Type::Number())) {
3007 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3008 315 : MachineRepresentation::kBit);
3009 315 : if (lower()) {
3010 : NodeProperties::ChangeOp(node,
3011 105 : lowering->simplified()->NumberIsFinite());
3012 : }
3013 : } else {
3014 21 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3015 : }
3016 : return;
3017 : }
3018 : case IrOpcode::kNumberIsFinite: {
3019 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3020 123 : MachineRepresentation::kBit);
3021 123 : return;
3022 : }
3023 : case IrOpcode::kObjectIsSafeInteger: {
3024 42 : Type const input_type = GetUpperBound(node->InputAt(0));
3025 84 : if (input_type.Is(type_cache_->kSafeInteger)) {
3026 0 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3027 0 : if (lower()) {
3028 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3029 : }
3030 42 : } else if (!input_type.Maybe(Type::Number())) {
3031 0 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3032 0 : if (lower()) {
3033 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3034 : }
3035 42 : } else if (input_type.Is(Type::Number())) {
3036 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3037 21 : MachineRepresentation::kBit);
3038 21 : if (lower()) {
3039 : NodeProperties::ChangeOp(
3040 7 : node, lowering->simplified()->NumberIsSafeInteger());
3041 : }
3042 : } else {
3043 21 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3044 : }
3045 : return;
3046 : }
3047 : case IrOpcode::kNumberIsSafeInteger: {
3048 0 : UNREACHABLE();
3049 : }
3050 : case IrOpcode::kObjectIsInteger: {
3051 588 : Type const input_type = GetUpperBound(node->InputAt(0));
3052 1176 : if (input_type.Is(type_cache_->kSafeInteger)) {
3053 210 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3054 210 : if (lower()) {
3055 70 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3056 : }
3057 378 : } else if (!input_type.Maybe(Type::Number())) {
3058 0 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3059 0 : if (lower()) {
3060 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3061 : }
3062 378 : } else if (input_type.Is(Type::Number())) {
3063 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3064 357 : MachineRepresentation::kBit);
3065 357 : if (lower()) {
3066 : NodeProperties::ChangeOp(node,
3067 119 : lowering->simplified()->NumberIsInteger());
3068 : }
3069 : } else {
3070 21 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3071 : }
3072 : return;
3073 : }
3074 : case IrOpcode::kNumberIsInteger: {
3075 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3076 0 : MachineRepresentation::kBit);
3077 0 : return;
3078 : }
3079 : case IrOpcode::kObjectIsMinusZero: {
3080 339 : Type const input_type = GetUpperBound(node->InputAt(0));
3081 339 : if (input_type.Is(Type::MinusZero())) {
3082 0 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3083 0 : if (lower()) {
3084 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3085 : }
3086 339 : } else if (!input_type.Maybe(Type::MinusZero())) {
3087 0 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3088 0 : if (lower()) {
3089 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3090 : }
3091 339 : } else if (input_type.Is(Type::Number())) {
3092 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3093 276 : MachineRepresentation::kBit);
3094 276 : if (lower()) {
3095 92 : NodeProperties::ChangeOp(node, simplified()->NumberIsMinusZero());
3096 : }
3097 : } else {
3098 63 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3099 : }
3100 : return;
3101 : }
3102 : case IrOpcode::kObjectIsNaN: {
3103 2745 : Type const input_type = GetUpperBound(node->InputAt(0));
3104 2745 : if (input_type.Is(Type::NaN())) {
3105 0 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3106 0 : if (lower()) {
3107 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3108 : }
3109 2745 : } else if (!input_type.Maybe(Type::NaN())) {
3110 39 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3111 39 : if (lower()) {
3112 13 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3113 : }
3114 2706 : } else if (input_type.Is(Type::Number())) {
3115 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3116 651 : MachineRepresentation::kBit);
3117 651 : if (lower()) {
3118 217 : NodeProperties::ChangeOp(node, simplified()->NumberIsNaN());
3119 : }
3120 : } else {
3121 2055 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3122 : }
3123 : return;
3124 : }
3125 : case IrOpcode::kNumberIsNaN: {
3126 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3127 31884 : MachineRepresentation::kBit);
3128 31884 : return;
3129 : }
3130 : case IrOpcode::kObjectIsNonCallable: {
3131 17933 : VisitObjectIs(node, Type::NonCallable(), lowering);
3132 17933 : return;
3133 : }
3134 : case IrOpcode::kObjectIsNumber: {
3135 22498 : VisitObjectIs(node, Type::Number(), lowering);
3136 22498 : return;
3137 : }
3138 : case IrOpcode::kObjectIsReceiver: {
3139 59466 : VisitObjectIs(node, Type::Receiver(), lowering);
3140 59465 : return;
3141 : }
3142 : case IrOpcode::kObjectIsSmi: {
3143 : // TODO(turbofan): Optimize based on input representation.
3144 5677 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3145 5677 : return;
3146 : }
3147 : case IrOpcode::kObjectIsString: {
3148 6054 : VisitObjectIs(node, Type::String(), lowering);
3149 6054 : return;
3150 : }
3151 : case IrOpcode::kObjectIsSymbol: {
3152 62 : VisitObjectIs(node, Type::Symbol(), lowering);
3153 62 : return;
3154 : }
3155 : case IrOpcode::kObjectIsUndetectable: {
3156 4466 : VisitObjectIs(node, Type::Undetectable(), lowering);
3157 4466 : return;
3158 : }
3159 : case IrOpcode::kArgumentsFrame: {
3160 : SetOutput(node, MachineType::PointerRepresentation());
3161 : return;
3162 : }
3163 : case IrOpcode::kArgumentsLength: {
3164 50164 : VisitUnop(node, UseInfo::Word(), MachineRepresentation::kTaggedSigned);
3165 50164 : return;
3166 : }
3167 : case IrOpcode::kNewDoubleElements:
3168 : case IrOpcode::kNewSmiOrObjectElements: {
3169 : VisitUnop(node, UseInfo::TruncatingWord32(),
3170 1821 : MachineRepresentation::kTaggedPointer);
3171 1821 : return;
3172 : }
3173 : case IrOpcode::kNewArgumentsElements: {
3174 : VisitBinop(node, UseInfo::Word(), UseInfo::TaggedSigned(),
3175 58768 : MachineRepresentation::kTaggedPointer);
3176 58768 : return;
3177 : }
3178 : case IrOpcode::kCheckFloat64Hole: {
3179 1878 : Type const input_type = TypeOf(node->InputAt(0));
3180 : CheckFloat64HoleMode mode =
3181 1878 : CheckFloat64HoleParametersOf(node->op()).mode();
3182 1878 : if (mode == CheckFloat64HoleMode::kAllowReturnHole) {
3183 : // If {mode} is allow-return-hole _and_ the {truncation}
3184 : // identifies NaN and undefined, we can just pass along
3185 : // the {truncation} and completely wipe the {node}.
3186 1329 : if (truncation.IsUnused()) return VisitUnused(node);
3187 1232 : if (truncation.IsUsedAsFloat64()) {
3188 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3189 111 : MachineRepresentation::kFloat64);
3190 148 : if (lower()) DeferReplacement(node, node->InputAt(0));
3191 : return;
3192 : }
3193 : }
3194 : VisitUnop(node,
3195 : UseInfo(MachineRepresentation::kFloat64, Truncation::Any()),
3196 3340 : MachineRepresentation::kFloat64, Type::Number());
3197 2206 : if (lower() && input_type.Is(Type::Number())) {
3198 65 : DeferReplacement(node, node->InputAt(0));
3199 : }
3200 : return;
3201 : }
3202 : case IrOpcode::kCheckNotTaggedHole: {
3203 291 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3204 291 : return;
3205 : }
3206 : case IrOpcode::kConvertTaggedHoleToUndefined: {
3207 8434 : if (InputIs(node, Type::NumberOrOddball()) &&
3208 : truncation.IsUsedAsWord32()) {
3209 : // Propagate the Word32 truncation.
3210 : VisitUnop(node, UseInfo::TruncatingWord32(),
3211 677 : MachineRepresentation::kWord32);
3212 844 : if (lower()) DeferReplacement(node, node->InputAt(0));
3213 7080 : } else if (InputIs(node, Type::NumberOrOddball()) &&
3214 : truncation.IsUsedAsFloat64()) {
3215 : // Propagate the Float64 truncation.
3216 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3217 101 : MachineRepresentation::kFloat64);
3218 133 : if (lower()) DeferReplacement(node, node->InputAt(0));
3219 5425 : } else if (InputIs(node, Type::NonInternal())) {
3220 139 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3221 185 : if (lower()) DeferReplacement(node, node->InputAt(0));
3222 : } else {
3223 : // TODO(turbofan): Add a (Tagged) truncation that identifies hole
3224 : // and undefined, i.e. for a[i] === obj cases.
3225 5286 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3226 : }
3227 : return;
3228 : }
3229 : case IrOpcode::kCheckEqualsSymbol:
3230 : case IrOpcode::kCheckEqualsInternalizedString:
3231 : return VisitBinop(node, UseInfo::AnyTagged(),
3232 : MachineRepresentation::kNone);
3233 : case IrOpcode::kMapGuard:
3234 : // Eliminate MapGuard nodes here.
3235 16490 : return VisitUnused(node);
3236 : case IrOpcode::kCheckMaps:
3237 : case IrOpcode::kTransitionElementsKind: {
3238 173635 : VisitInputs(node);
3239 : return SetOutput(node, MachineRepresentation::kNone);
3240 : }
3241 : case IrOpcode::kCompareMaps:
3242 : return VisitUnop(node, UseInfo::AnyTagged(),
3243 18525 : MachineRepresentation::kBit);
3244 : case IrOpcode::kEnsureWritableFastElements:
3245 : return VisitBinop(node, UseInfo::AnyTagged(),
3246 : MachineRepresentation::kTaggedPointer);
3247 : case IrOpcode::kMaybeGrowFastElements: {
3248 12082 : Type const index_type = TypeOf(node->InputAt(2));
3249 12082 : Type const length_type = TypeOf(node->InputAt(3));
3250 12082 : ProcessInput(node, 0, UseInfo::AnyTagged()); // object
3251 12082 : ProcessInput(node, 1, UseInfo::AnyTagged()); // elements
3252 12082 : ProcessInput(node, 2, UseInfo::TruncatingWord32()); // index
3253 12082 : ProcessInput(node, 3, UseInfo::TruncatingWord32()); // length
3254 12082 : ProcessRemainingInputs(node, 4);
3255 : SetOutput(node, MachineRepresentation::kTaggedPointer);
3256 12082 : if (lower()) {
3257 : // If the index is known to be less than the length (or if
3258 : // we're in dead code), we know that we don't need to grow
3259 : // the elements, so we can just remove this operation all
3260 : // together and replace it with the elements that we have
3261 : // on the inputs.
3262 11148 : if (index_type.IsNone() || length_type.IsNone() ||
3263 3716 : index_type.Max() < length_type.Min()) {
3264 51 : DeferReplacement(node, node->InputAt(1));
3265 : }
3266 : }
3267 : return;
3268 : }
3269 :
3270 : case IrOpcode::kDateNow:
3271 21 : VisitInputs(node);
3272 : return SetOutput(node, MachineRepresentation::kTaggedPointer);
3273 : case IrOpcode::kFrameState:
3274 14970969 : return VisitFrameState(node);
3275 : case IrOpcode::kStateValues:
3276 9229011 : return VisitStateValues(node);
3277 : case IrOpcode::kObjectState:
3278 70771 : return VisitObjectState(node);
3279 : case IrOpcode::kObjectId:
3280 : return SetOutput(node, MachineRepresentation::kTaggedPointer);
3281 : case IrOpcode::kTypeGuard: {
3282 : // We just get rid of the sigma here, choosing the best representation
3283 : // for the sigma's type.
3284 86216 : Type type = TypeOf(node);
3285 : MachineRepresentation representation =
3286 86216 : GetOutputInfoForPhi(node, type, truncation);
3287 :
3288 : // Here we pretend that the input has the sigma's type for the
3289 : // conversion.
3290 172440 : UseInfo use(representation, truncation);
3291 86219 : if (propagate()) {
3292 28822 : EnqueueInput(node, 0, use);
3293 57397 : } else if (lower()) {
3294 20502 : ConvertInput(node, 0, use, type);
3295 : }
3296 86220 : ProcessRemainingInputs(node, 1);
3297 : SetOutput(node, representation);
3298 : return;
3299 : }
3300 :
3301 : case IrOpcode::kFinishRegion:
3302 388493 : VisitInputs(node);
3303 : // Assume the output is tagged pointer.
3304 : return SetOutput(node, MachineRepresentation::kTaggedPointer);
3305 :
3306 : case IrOpcode::kReturn:
3307 1625871 : VisitReturn(node);
3308 : // Assume the output is tagged.
3309 : return SetOutput(node, MachineRepresentation::kTagged);
3310 :
3311 : case IrOpcode::kFindOrderedHashMapEntry: {
3312 725 : Type const key_type = TypeOf(node->InputAt(1));
3313 725 : if (key_type.Is(Type::Signed32OrMinusZero())) {
3314 : VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
3315 60 : MachineType::PointerRepresentation());
3316 60 : if (lower()) {
3317 : NodeProperties::ChangeOp(
3318 : node,
3319 15 : lowering->simplified()->FindOrderedHashMapEntryForInt32Key());
3320 : }
3321 : } else {
3322 : VisitBinop(node, UseInfo::AnyTagged(),
3323 : MachineRepresentation::kTaggedSigned);
3324 : }
3325 : return;
3326 : }
3327 :
3328 : // Operators with all inputs tagged and no or tagged output have uniform
3329 : // handling.
3330 : case IrOpcode::kEnd:
3331 : case IrOpcode::kIfSuccess:
3332 : case IrOpcode::kIfException:
3333 : case IrOpcode::kIfTrue:
3334 : case IrOpcode::kIfFalse:
3335 : case IrOpcode::kIfValue:
3336 : case IrOpcode::kIfDefault:
3337 : case IrOpcode::kDeoptimize:
3338 : case IrOpcode::kEffectPhi:
3339 : case IrOpcode::kTerminate:
3340 : case IrOpcode::kCheckpoint:
3341 : case IrOpcode::kLoop:
3342 : case IrOpcode::kMerge:
3343 : case IrOpcode::kThrow:
3344 : case IrOpcode::kBeginRegion:
3345 : case IrOpcode::kProjection:
3346 : case IrOpcode::kOsrValue:
3347 : case IrOpcode::kArgumentsElementsState:
3348 : case IrOpcode::kArgumentsLengthState:
3349 : case IrOpcode::kUnreachable:
3350 : case IrOpcode::kRuntimeAbort:
3351 : // All JavaScript operators except JSToNumber have uniform handling.
3352 : #define OPCODE_CASE(name) case IrOpcode::k##name:
3353 : JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
3354 : JS_OBJECT_OP_LIST(OPCODE_CASE)
3355 : JS_CONTEXT_OP_LIST(OPCODE_CASE)
3356 : JS_OTHER_OP_LIST(OPCODE_CASE)
3357 : #undef OPCODE_CASE
3358 : case IrOpcode::kJSBitwiseNot:
3359 : case IrOpcode::kJSDecrement:
3360 : case IrOpcode::kJSIncrement:
3361 : case IrOpcode::kJSNegate:
3362 : case IrOpcode::kJSToLength:
3363 : case IrOpcode::kJSToName:
3364 : case IrOpcode::kJSToObject:
3365 : case IrOpcode::kJSToString:
3366 : case IrOpcode::kJSParseInt:
3367 26093621 : VisitInputs(node);
3368 : // Assume the output is tagged.
3369 : return SetOutput(node, MachineRepresentation::kTagged);
3370 : case IrOpcode::kDeadValue:
3371 1422 : ProcessInput(node, 0, UseInfo::Any());
3372 : return SetOutput(node, MachineRepresentation::kNone);
3373 : default:
3374 0 : FATAL(
3375 : "Representation inference: unsupported opcode %i (%s), node #%i\n.",
3376 0 : node->opcode(), node->op()->mnemonic(), node->id());
3377 : break;
3378 : }
3379 : UNREACHABLE();
3380 : }
3381 :
3382 1386417 : void DeferReplacement(Node* node, Node* replacement) {
3383 2893250 : TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
3384 : node->op()->mnemonic(), replacement->id(),
3385 : replacement->op()->mnemonic());
3386 :
3387 : // Disconnect the node from effect and control chains, if necessary.
3388 4159278 : if (node->op()->EffectInputCount() > 0) {
3389 : DCHECK_LT(0, node->op()->ControlInputCount());
3390 : // Disconnect the node from effect and control chains.
3391 120407 : Node* control = NodeProperties::GetControlInput(node);
3392 120407 : Node* effect = NodeProperties::GetEffectInput(node);
3393 240814 : ReplaceEffectControlUses(node, effect, control);
3394 : }
3395 :
3396 1386426 : replacements_.push_back(node);
3397 1386436 : replacements_.push_back(replacement);
3398 :
3399 1386431 : node->NullAllInputs(); // Node is now dead.
3400 1386419 : }
3401 :
3402 94768 : void Kill(Node* node) {
3403 31594 : TRACE("killing #%d:%s\n", node->id(), node->op()->mnemonic());
3404 :
3405 31594 : if (node->op()->EffectInputCount() == 1) {
3406 : DCHECK_LT(0, node->op()->ControlInputCount());
3407 : // Disconnect the node from effect and control chains.
3408 31580 : Node* control = NodeProperties::GetControlInput(node);
3409 31580 : Node* effect = NodeProperties::GetEffectInput(node);
3410 31580 : ReplaceEffectControlUses(node, effect, control);
3411 : } else {
3412 : DCHECK_EQ(0, node->op()->EffectInputCount());
3413 : DCHECK_EQ(0, node->op()->ControlOutputCount());
3414 : DCHECK_EQ(0, node->op()->EffectOutputCount());
3415 : }
3416 :
3417 31594 : node->ReplaceUses(jsgraph_->Dead());
3418 :
3419 31593 : node->NullAllInputs(); // The {node} is now dead.
3420 31594 : }
3421 :
3422 47781980 : void PrintOutputInfo(NodeInfo* info) {
3423 47781980 : if (FLAG_trace_representation) {
3424 0 : StdoutStream{} << info->representation();
3425 : }
3426 47781980 : }
3427 :
3428 : void PrintRepresentation(MachineRepresentation rep) {
3429 : if (FLAG_trace_representation) {
3430 : StdoutStream{} << rep;
3431 : }
3432 : }
3433 :
3434 90440938 : void PrintTruncation(Truncation truncation) {
3435 90440938 : if (FLAG_trace_representation) {
3436 0 : StdoutStream{} << truncation.description() << std::endl;
3437 : }
3438 90440938 : }
3439 :
3440 15353256 : void PrintUseInfo(UseInfo info) {
3441 15353256 : if (FLAG_trace_representation) {
3442 0 : StdoutStream{} << info.representation() << ":"
3443 0 : << info.truncation().description();
3444 : }
3445 15353256 : }
3446 :
3447 : private:
3448 : JSGraph* jsgraph_;
3449 : Zone* zone_; // Temporary zone.
3450 : size_t const count_; // number of nodes in the graph
3451 : ZoneVector<NodeInfo> info_; // node id -> usage information
3452 : #ifdef DEBUG
3453 : ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
3454 : // requirements on inputs.
3455 : #endif // DEBUG
3456 : NodeVector nodes_; // collected nodes
3457 : NodeVector replacements_; // replacements to be done after lowering
3458 : Phase phase_; // current phase of algorithm
3459 : RepresentationChanger* changer_; // for inserting representation changes
3460 : ZoneQueue<Node*> queue_; // queue for traversing the graph
3461 :
3462 : struct NodeState {
3463 : Node* node;
3464 : int input_index;
3465 : };
3466 : ZoneStack<NodeState> typing_stack_; // stack for graph typing.
3467 : // TODO(danno): RepresentationSelector shouldn't know anything about the
3468 : // source positions table, but must for now since there currently is no other
3469 : // way to pass down source position information to nodes created during
3470 : // lowering. Once this phase becomes a vanilla reducer, it should get source
3471 : // position information via the SourcePositionWrapper like all other reducers.
3472 : SourcePositionTable* source_positions_;
3473 : NodeOriginTable* node_origins_;
3474 : TypeCache const* type_cache_;
3475 : OperationTyper op_typer_; // helper for the feedback typer
3476 :
3477 628948052 : NodeInfo* GetInfo(Node* node) {
3478 : DCHECK(node->id() < count_);
3479 632486253 : return &info_[node->id()];
3480 : }
3481 : Zone* zone() { return zone_; }
3482 : Zone* graph_zone() { return jsgraph_->zone(); }
3483 : };
3484 :
3485 456096 : SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker,
3486 : Zone* zone,
3487 : SourcePositionTable* source_positions,
3488 : NodeOriginTable* node_origins,
3489 : PoisoningMitigationLevel poisoning_level)
3490 : : jsgraph_(jsgraph),
3491 : broker_(broker),
3492 : zone_(zone),
3493 456096 : type_cache_(TypeCache::Get()),
3494 : source_positions_(source_positions),
3495 : node_origins_(node_origins),
3496 912210 : poisoning_level_(poisoning_level) {}
3497 :
3498 912214 : void SimplifiedLowering::LowerAllNodes() {
3499 456096 : RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
3500 : RepresentationSelector selector(jsgraph(), broker_, zone_, &changer,
3501 912236 : source_positions_, node_origins_);
3502 456130 : selector.Run(this);
3503 456127 : }
3504 :
3505 1413 : void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
3506 2826 : Node* node, RepresentationSelector* selector) {
3507 : DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
3508 : node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
3509 : node->opcode() == IrOpcode::kJSToNumeric);
3510 : Node* value = node->InputAt(0);
3511 : Node* context = node->InputAt(1);
3512 : Node* frame_state = node->InputAt(2);
3513 : Node* effect = node->InputAt(3);
3514 : Node* control = node->InputAt(4);
3515 :
3516 1413 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
3517 : Node* branch0 =
3518 1413 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
3519 :
3520 1413 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3521 : Node* etrue0 = effect;
3522 : Node* vtrue0;
3523 : {
3524 1413 : vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
3525 1413 : vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
3526 : }
3527 :
3528 1413 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3529 : Node* efalse0 = effect;
3530 : Node* vfalse0;
3531 : {
3532 : Operator const* op =
3533 : node->opcode() == IrOpcode::kJSToNumber
3534 : ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3535 : ? ToNumberConvertBigIntOperator()
3536 : : ToNumberOperator())
3537 1413 : : ToNumericOperator();
3538 : Node* code = node->opcode() == IrOpcode::kJSToNumber
3539 : ? ToNumberCode()
3540 : : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3541 : ? ToNumberConvertBigIntCode()
3542 1413 : : ToNumericCode());
3543 : vfalse0 = efalse0 = if_false0 = graph()->NewNode(
3544 : op, code, value, context, frame_state, efalse0, if_false0);
3545 :
3546 : // Update potential {IfException} uses of {node} to point to the above
3547 : // stub call node instead.
3548 1413 : Node* on_exception = nullptr;
3549 1413 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3550 0 : NodeProperties::ReplaceControlInput(on_exception, vfalse0);
3551 0 : NodeProperties::ReplaceEffectInput(on_exception, efalse0);
3552 0 : if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
3553 : }
3554 :
3555 1413 : Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
3556 1413 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3557 :
3558 1413 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3559 : Node* etrue1 = efalse0;
3560 : Node* vtrue1;
3561 : {
3562 : vtrue1 =
3563 1413 : graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
3564 1413 : vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
3565 : }
3566 :
3567 1413 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3568 : Node* efalse1 = efalse0;
3569 : Node* vfalse1;
3570 : {
3571 : vfalse1 = efalse1 = graph()->NewNode(
3572 : simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
3573 4239 : efalse1, if_false1);
3574 : }
3575 :
3576 1413 : if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
3577 : efalse0 =
3578 1413 : graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
3579 : vfalse0 =
3580 : graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
3581 1413 : vtrue1, vfalse1, if_false0);
3582 : }
3583 :
3584 1413 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
3585 1413 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
3586 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
3587 1413 : vtrue0, vfalse0, control);
3588 :
3589 : // Replace effect and control uses appropriately.
3590 11306 : for (Edge edge : node->use_edges()) {
3591 4240 : if (NodeProperties::IsControlEdge(edge)) {
3592 4239 : if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
3593 0 : edge.from()->ReplaceUses(control);
3594 0 : edge.from()->Kill();
3595 : } else {
3596 : DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
3597 1413 : edge.UpdateTo(control);
3598 : }
3599 2827 : } else if (NodeProperties::IsEffectEdge(edge)) {
3600 1414 : edge.UpdateTo(effect);
3601 : }
3602 : }
3603 :
3604 1413 : selector->DeferReplacement(node, value);
3605 1413 : }
3606 :
3607 72 : void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
3608 144 : Node* node, RepresentationSelector* selector) {
3609 : DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
3610 : node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
3611 : node->opcode() == IrOpcode::kJSToNumeric);
3612 : Node* value = node->InputAt(0);
3613 : Node* context = node->InputAt(1);
3614 : Node* frame_state = node->InputAt(2);
3615 : Node* effect = node->InputAt(3);
3616 : Node* control = node->InputAt(4);
3617 :
3618 72 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
3619 : Node* branch0 =
3620 72 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
3621 :
3622 72 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3623 : Node* etrue0 = effect;
3624 : Node* vtrue0 =
3625 72 : graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
3626 :
3627 72 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3628 : Node* efalse0 = effect;
3629 : Node* vfalse0;
3630 : {
3631 : Operator const* op =
3632 : node->opcode() == IrOpcode::kJSToNumber
3633 : ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3634 : ? ToNumberConvertBigIntOperator()
3635 : : ToNumberOperator())
3636 72 : : ToNumericOperator();
3637 : Node* code = node->opcode() == IrOpcode::kJSToNumber
3638 : ? ToNumberCode()
3639 : : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3640 : ? ToNumberConvertBigIntCode()
3641 72 : : ToNumericCode());
3642 : vfalse0 = efalse0 = if_false0 = graph()->NewNode(
3643 : op, code, value, context, frame_state, efalse0, if_false0);
3644 :
3645 : // Update potential {IfException} uses of {node} to point to the above
3646 : // stub call node instead.
3647 72 : Node* on_exception = nullptr;
3648 72 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3649 0 : NodeProperties::ReplaceControlInput(on_exception, vfalse0);
3650 0 : NodeProperties::ReplaceEffectInput(on_exception, efalse0);
3651 0 : if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
3652 : }
3653 :
3654 72 : Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
3655 72 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3656 :
3657 72 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3658 : Node* etrue1 = efalse0;
3659 : Node* vtrue1 =
3660 72 : graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
3661 :
3662 72 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3663 : Node* efalse1 = efalse0;
3664 : Node* vfalse1;
3665 : {
3666 : vfalse1 = efalse1 = graph()->NewNode(
3667 : simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
3668 216 : efalse1, if_false1);
3669 72 : vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
3670 : }
3671 :
3672 72 : if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
3673 : efalse0 =
3674 72 : graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
3675 : vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
3676 72 : vtrue1, vfalse1, if_false0);
3677 : }
3678 :
3679 72 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
3680 72 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
3681 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
3682 72 : vtrue0, vfalse0, control);
3683 :
3684 : // Replace effect and control uses appropriately.
3685 520 : for (Edge edge : node->use_edges()) {
3686 188 : if (NodeProperties::IsControlEdge(edge)) {
3687 339 : if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
3688 0 : edge.from()->ReplaceUses(control);
3689 0 : edge.from()->Kill();
3690 : } else {
3691 : DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
3692 113 : edge.UpdateTo(control);
3693 : }
3694 75 : } else if (NodeProperties::IsEffectEdge(edge)) {
3695 72 : edge.UpdateTo(effect);
3696 : }
3697 : }
3698 :
3699 72 : selector->DeferReplacement(node, value);
3700 72 : }
3701 :
3702 3112 : Node* SimplifiedLowering::Float64Round(Node* const node) {
3703 1556 : Node* const one = jsgraph()->Float64Constant(1.0);
3704 1556 : Node* const one_half = jsgraph()->Float64Constant(0.5);
3705 : Node* const input = node->InputAt(0);
3706 :
3707 : // Round up towards Infinity, and adjust if the difference exceeds 0.5.
3708 : Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
3709 3112 : node->InputAt(0));
3710 : return graph()->NewNode(
3711 : common()->Select(MachineRepresentation::kFloat64),
3712 : graph()->NewNode(
3713 : machine()->Float64LessThanOrEqual(),
3714 : graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
3715 7780 : result, graph()->NewNode(machine()->Float64Sub(), result, one));
3716 : }
3717 :
3718 90 : Node* SimplifiedLowering::Float64Sign(Node* const node) {
3719 30 : Node* const minus_one = jsgraph()->Float64Constant(-1.0);
3720 30 : Node* const zero = jsgraph()->Float64Constant(0.0);
3721 30 : Node* const one = jsgraph()->Float64Constant(1.0);
3722 :
3723 : Node* const input = node->InputAt(0);
3724 :
3725 : return graph()->NewNode(
3726 : common()->Select(MachineRepresentation::kFloat64),
3727 : graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
3728 : graph()->NewNode(
3729 : common()->Select(MachineRepresentation::kFloat64),
3730 : graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
3731 150 : input));
3732 : }
3733 :
3734 166 : Node* SimplifiedLowering::Int32Abs(Node* const node) {
3735 : Node* const input = node->InputAt(0);
3736 :
3737 : // Generate case for absolute integer value.
3738 : //
3739 : // let sign = input >> 31 in
3740 : // (input ^ sign) - sign
3741 :
3742 : Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
3743 166 : jsgraph()->Int32Constant(31));
3744 : return graph()->NewNode(machine()->Int32Sub(),
3745 : graph()->NewNode(machine()->Word32Xor(), input, sign),
3746 249 : sign);
3747 : }
3748 :
3749 8355 : Node* SimplifiedLowering::Int32Div(Node* const node) {
3750 2785 : Int32BinopMatcher m(node);
3751 2785 : Node* const zero = jsgraph()->Int32Constant(0);
3752 2785 : Node* const minus_one = jsgraph()->Int32Constant(-1);
3753 : Node* const lhs = m.left().node();
3754 : Node* const rhs = m.right().node();
3755 :
3756 2785 : if (m.right().Is(-1)) {
3757 30 : return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3758 2770 : } else if (m.right().Is(0)) {
3759 : return rhs;
3760 2770 : } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
3761 4182 : return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
3762 : }
3763 :
3764 : // General case for signed integer division.
3765 : //
3766 : // if 0 < rhs then
3767 : // lhs / rhs
3768 : // else
3769 : // if rhs < -1 then
3770 : // lhs / rhs
3771 : // else if rhs == 0 then
3772 : // 0
3773 : // else
3774 : // 0 - lhs
3775 : //
3776 : // Note: We do not use the Diamond helper class here, because it really hurts
3777 : // readability with nested diamonds.
3778 679 : const Operator* const merge_op = common()->Merge(2);
3779 : const Operator* const phi_op =
3780 679 : common()->Phi(MachineRepresentation::kWord32, 2);
3781 :
3782 679 : Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3783 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3784 1358 : graph()->start());
3785 :
3786 679 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3787 679 : Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
3788 :
3789 679 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3790 : Node* false0;
3791 : {
3792 679 : Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3793 679 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3794 :
3795 679 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3796 679 : Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
3797 :
3798 679 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3799 : Node* false1;
3800 : {
3801 679 : Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3802 679 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
3803 :
3804 679 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3805 : Node* true2 = zero;
3806 :
3807 679 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3808 679 : Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3809 :
3810 : if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3811 : false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3812 : }
3813 :
3814 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3815 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3816 : }
3817 :
3818 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3819 679 : return graph()->NewNode(phi_op, true0, false0, merge0);
3820 : }
3821 :
3822 6705 : Node* SimplifiedLowering::Int32Mod(Node* const node) {
3823 2235 : Int32BinopMatcher m(node);
3824 2235 : Node* const zero = jsgraph()->Int32Constant(0);
3825 2235 : Node* const minus_one = jsgraph()->Int32Constant(-1);
3826 : Node* const lhs = m.left().node();
3827 : Node* const rhs = m.right().node();
3828 :
3829 4463 : if (m.right().Is(-1) || m.right().Is(0)) {
3830 : return zero;
3831 2228 : } else if (m.right().HasValue()) {
3832 6447 : return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
3833 : }
3834 :
3835 : // General case for signed integer modulus, with optimization for (unknown)
3836 : // power of 2 right hand side.
3837 : //
3838 : // if 0 < rhs then
3839 : // msk = rhs - 1
3840 : // if rhs & msk != 0 then
3841 : // lhs % rhs
3842 : // else
3843 : // if lhs < 0 then
3844 : // -(-lhs & msk)
3845 : // else
3846 : // lhs & msk
3847 : // else
3848 : // if rhs < -1 then
3849 : // lhs % rhs
3850 : // else
3851 : // zero
3852 : //
3853 : // Note: We do not use the Diamond helper class here, because it really hurts
3854 : // readability with nested diamonds.
3855 79 : const Operator* const merge_op = common()->Merge(2);
3856 : const Operator* const phi_op =
3857 79 : common()->Phi(MachineRepresentation::kWord32, 2);
3858 :
3859 79 : Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3860 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3861 158 : graph()->start());
3862 :
3863 79 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3864 : Node* true0;
3865 : {
3866 79 : Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3867 :
3868 79 : Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3869 79 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
3870 :
3871 79 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3872 79 : Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3873 :
3874 79 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3875 : Node* false1;
3876 : {
3877 79 : Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
3878 : Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
3879 79 : check2, if_false1);
3880 :
3881 79 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3882 : Node* true2 = graph()->NewNode(
3883 : machine()->Int32Sub(), zero,
3884 : graph()->NewNode(machine()->Word32And(),
3885 : graph()->NewNode(machine()->Int32Sub(), zero, lhs),
3886 237 : msk));
3887 :
3888 79 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3889 79 : Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
3890 :
3891 : if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3892 : false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3893 : }
3894 :
3895 : if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
3896 : true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
3897 : }
3898 :
3899 79 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3900 : Node* false0;
3901 : {
3902 79 : Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3903 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
3904 79 : check1, if_false0);
3905 :
3906 79 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3907 79 : Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3908 :
3909 79 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3910 : Node* false1 = zero;
3911 :
3912 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3913 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3914 : }
3915 :
3916 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3917 79 : return graph()->NewNode(phi_op, true0, false0, merge0);
3918 : }
3919 :
3920 21 : Node* SimplifiedLowering::Int32Sign(Node* const node) {
3921 7 : Node* const minus_one = jsgraph()->Int32Constant(-1);
3922 7 : Node* const zero = jsgraph()->Int32Constant(0);
3923 7 : Node* const one = jsgraph()->Int32Constant(1);
3924 :
3925 : Node* const input = node->InputAt(0);
3926 :
3927 : return graph()->NewNode(
3928 : common()->Select(MachineRepresentation::kWord32),
3929 : graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
3930 : graph()->NewNode(
3931 : common()->Select(MachineRepresentation::kWord32),
3932 : graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
3933 35 : zero));
3934 : }
3935 :
3936 508 : Node* SimplifiedLowering::Uint32Div(Node* const node) {
3937 254 : Uint32BinopMatcher m(node);
3938 254 : Node* const zero = jsgraph()->Uint32Constant(0);
3939 : Node* const lhs = m.left().node();
3940 : Node* const rhs = m.right().node();
3941 :
3942 254 : if (m.right().Is(0)) {
3943 : return zero;
3944 247 : } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
3945 400 : return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
3946 : }
3947 :
3948 47 : Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3949 47 : Diamond d(graph(), common(), check, BranchHint::kFalse);
3950 94 : Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
3951 47 : return d.Phi(MachineRepresentation::kWord32, zero, div);
3952 : }
3953 :
3954 720 : Node* SimplifiedLowering::Uint32Mod(Node* const node) {
3955 240 : Uint32BinopMatcher m(node);
3956 240 : Node* const minus_one = jsgraph()->Int32Constant(-1);
3957 240 : Node* const zero = jsgraph()->Uint32Constant(0);
3958 : Node* const lhs = m.left().node();
3959 : Node* const rhs = m.right().node();
3960 :
3961 240 : if (m.right().Is(0)) {
3962 : return zero;
3963 240 : } else if (m.right().HasValue()) {
3964 612 : return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
3965 : }
3966 :
3967 : // General case for unsigned integer modulus, with optimization for (unknown)
3968 : // power of 2 right hand side.
3969 : //
3970 : // if rhs == 0 then
3971 : // zero
3972 : // else
3973 : // msk = rhs - 1
3974 : // if rhs & msk != 0 then
3975 : // lhs % rhs
3976 : // else
3977 : // lhs & msk
3978 : //
3979 : // Note: We do not use the Diamond helper class here, because it really hurts
3980 : // readability with nested diamonds.
3981 36 : const Operator* const merge_op = common()->Merge(2);
3982 : const Operator* const phi_op =
3983 36 : common()->Phi(MachineRepresentation::kWord32, 2);
3984 :
3985 36 : Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3986 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
3987 72 : graph()->start());
3988 :
3989 36 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3990 : Node* true0 = zero;
3991 :
3992 36 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3993 : Node* false0;
3994 : {
3995 36 : Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3996 :
3997 36 : Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3998 36 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3999 :
4000 36 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4001 36 : Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
4002 :
4003 36 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4004 36 : Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
4005 :
4006 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4007 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4008 : }
4009 :
4010 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4011 36 : return graph()->NewNode(phi_op, true0, false0, merge0);
4012 : }
4013 :
4014 2355 : void SimplifiedLowering::DoMax(Node* node, Operator const* op,
4015 : MachineRepresentation rep) {
4016 : Node* const lhs = node->InputAt(0);
4017 : Node* const rhs = node->InputAt(1);
4018 :
4019 2355 : node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
4020 : DCHECK_EQ(rhs, node->InputAt(1));
4021 2355 : node->AppendInput(graph()->zone(), lhs);
4022 2355 : NodeProperties::ChangeOp(node, common()->Select(rep));
4023 2355 : }
4024 :
4025 3132 : void SimplifiedLowering::DoMin(Node* node, Operator const* op,
4026 : MachineRepresentation rep) {
4027 : Node* const lhs = node->InputAt(0);
4028 : Node* const rhs = node->InputAt(1);
4029 :
4030 3132 : node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
4031 : DCHECK_EQ(lhs, node->InputAt(1));
4032 : DCHECK_EQ(rhs, node->InputAt(2));
4033 3132 : NodeProperties::ChangeOp(node, common()->Select(rep));
4034 3132 : }
4035 :
4036 306 : void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
4037 : Node* const input = node->InputAt(0);
4038 153 : Node* const zero = jsgraph()->Int32Constant(0);
4039 153 : Operator const* const op = machine()->Word32Equal();
4040 :
4041 153 : node->ReplaceInput(0, graph()->NewNode(op, input, zero));
4042 153 : node->AppendInput(graph()->zone(), zero);
4043 153 : NodeProperties::ChangeOp(node, op);
4044 153 : }
4045 :
4046 0 : void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
4047 : Node* const input = node->InputAt(0);
4048 :
4049 : node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
4050 0 : jsgraph()->Float64Constant(0.0)));
4051 0 : node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
4052 0 : NodeProperties::ChangeOp(node, machine()->Word32Equal());
4053 0 : }
4054 :
4055 66 : void SimplifiedLowering::DoNumberToBit(Node* node) {
4056 : Node* const input = node->InputAt(0);
4057 :
4058 33 : node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
4059 : node->AppendInput(graph()->zone(),
4060 66 : graph()->NewNode(machine()->Float64Abs(), input));
4061 33 : NodeProperties::ChangeOp(node, machine()->Float64LessThan());
4062 33 : }
4063 :
4064 63 : void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
4065 : Node* const input = node->InputAt(0);
4066 21 : Node* const min = jsgraph()->Float64Constant(0.0);
4067 21 : Node* const max = jsgraph()->Float64Constant(255.0);
4068 :
4069 : node->ReplaceInput(
4070 42 : 0, graph()->NewNode(machine()->Float64LessThan(), min, input));
4071 : node->AppendInput(
4072 : graph()->zone(),
4073 : graph()->NewNode(
4074 : common()->Select(MachineRepresentation::kFloat64),
4075 : graph()->NewNode(machine()->Float64LessThan(), input, max), input,
4076 63 : max));
4077 21 : node->AppendInput(graph()->zone(), min);
4078 : NodeProperties::ChangeOp(node,
4079 21 : common()->Select(MachineRepresentation::kFloat64));
4080 21 : }
4081 :
4082 882 : void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
4083 : Node* const input = node->InputAt(0);
4084 294 : Node* const min = jsgraph()->Float64Constant(0.0);
4085 294 : Node* const max = jsgraph()->Float64Constant(255.0);
4086 :
4087 : node->ReplaceInput(
4088 : 0, graph()->NewNode(
4089 : common()->Select(MachineRepresentation::kFloat64),
4090 : graph()->NewNode(machine()->Float64LessThan(), min, input),
4091 : graph()->NewNode(
4092 : common()->Select(MachineRepresentation::kFloat64),
4093 : graph()->NewNode(machine()->Float64LessThan(), input, max),
4094 : input, max),
4095 1470 : min));
4096 : NodeProperties::ChangeOp(node,
4097 294 : machine()->Float64RoundTiesEven().placeholder());
4098 294 : }
4099 :
4100 192 : void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
4101 : Node* const input = node->InputAt(0);
4102 64 : Node* const min = jsgraph()->Int32Constant(0);
4103 64 : Node* const max = jsgraph()->Int32Constant(255);
4104 :
4105 : node->ReplaceInput(
4106 128 : 0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
4107 : node->AppendInput(
4108 : graph()->zone(),
4109 : graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
4110 : graph()->NewNode(machine()->Int32LessThan(), input, min),
4111 192 : min, input));
4112 64 : node->AppendInput(graph()->zone(), max);
4113 : NodeProperties::ChangeOp(node,
4114 64 : common()->Select(MachineRepresentation::kWord32));
4115 64 : }
4116 :
4117 144 : void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
4118 : Node* const input = node->InputAt(0);
4119 72 : Node* const max = jsgraph()->Uint32Constant(255u);
4120 :
4121 : node->ReplaceInput(
4122 144 : 0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
4123 72 : node->AppendInput(graph()->zone(), input);
4124 72 : node->AppendInput(graph()->zone(), max);
4125 : NodeProperties::ChangeOp(node,
4126 72 : common()->Select(MachineRepresentation::kWord32));
4127 72 : }
4128 :
4129 4251 : Node* SimplifiedLowering::ToNumberCode() {
4130 1417 : if (!to_number_code_.is_set()) {
4131 1417 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
4132 2834 : to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
4133 : }
4134 1417 : return to_number_code_.get();
4135 : }
4136 :
4137 204 : Node* SimplifiedLowering::ToNumberConvertBigIntCode() {
4138 68 : if (!to_number_convert_big_int_code_.is_set()) {
4139 : Callable callable =
4140 68 : Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
4141 : to_number_convert_big_int_code_.set(
4142 136 : jsgraph()->HeapConstant(callable.code()));
4143 : }
4144 68 : return to_number_convert_big_int_code_.get();
4145 : }
4146 :
4147 0 : Node* SimplifiedLowering::ToNumericCode() {
4148 0 : if (!to_numeric_code_.is_set()) {
4149 0 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
4150 0 : to_numeric_code_.set(jsgraph()->HeapConstant(callable.code()));
4151 : }
4152 0 : return to_numeric_code_.get();
4153 : }
4154 :
4155 2834 : Operator const* SimplifiedLowering::ToNumberOperator() {
4156 1417 : if (!to_number_operator_.is_set()) {
4157 1417 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
4158 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4159 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4160 : graph()->zone(), callable.descriptor(),
4161 : callable.descriptor().GetStackParameterCount(), flags,
4162 2834 : Operator::kNoProperties);
4163 1417 : to_number_operator_.set(common()->Call(call_descriptor));
4164 : }
4165 1417 : return to_number_operator_.get();
4166 : }
4167 :
4168 0 : Operator const* SimplifiedLowering::ToNumberConvertBigIntOperator() {
4169 0 : if (!to_number_convert_big_int_operator_.is_set()) {
4170 : Callable callable =
4171 0 : Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
4172 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4173 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4174 : graph()->zone(), callable.descriptor(),
4175 : callable.descriptor().GetStackParameterCount(), flags,
4176 0 : Operator::kNoProperties);
4177 0 : to_number_convert_big_int_operator_.set(common()->Call(call_descriptor));
4178 : }
4179 0 : return to_number_convert_big_int_operator_.get();
4180 : }
4181 :
4182 136 : Operator const* SimplifiedLowering::ToNumericOperator() {
4183 68 : if (!to_numeric_operator_.is_set()) {
4184 68 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
4185 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4186 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4187 : graph()->zone(), callable.descriptor(),
4188 : callable.descriptor().GetStackParameterCount(), flags,
4189 136 : Operator::kNoProperties);
4190 68 : to_numeric_operator_.set(common()->Call(call_descriptor));
4191 : }
4192 68 : return to_numeric_operator_.get();
4193 : }
4194 :
4195 : #undef TRACE
4196 :
4197 : } // namespace compiler
4198 : } // namespace internal
4199 183867 : } // namespace v8
|