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