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 33806 : MachineRepresentation MachineRepresentationFromArrayType(
70 : ExternalArrayType array_type) {
71 33806 : switch (array_type) {
72 : case kExternalUint8Array:
73 : case kExternalUint8ClampedArray:
74 : case kExternalInt8Array:
75 : return MachineRepresentation::kWord8;
76 : case kExternalUint16Array:
77 : case kExternalInt16Array:
78 5162 : return MachineRepresentation::kWord16;
79 : case kExternalUint32Array:
80 : case kExternalInt32Array:
81 6509 : 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 1079835 : UseInfo CheckedUseInfoAsWord32FromHint(
94 : NumberOperationHint hint, const VectorSlotPair& feedback = VectorSlotPair(),
95 : IdentifyZeros identify_zeros = kDistinguishZeros) {
96 1079835 : 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 166273 : UseInfo CheckedUseInfoAsFloat64FromHint(
111 : NumberOperationHint hint, const VectorSlotPair& feedback,
112 : IdentifyZeros identify_zeros = kDistinguishZeros) {
113 166273 : 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 8139461 : UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
129 8139461 : 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 10028204 : UseInfo UseInfoForBasePointer(const FieldAccess& access) {
160 20056413 : return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
161 : }
162 :
163 181619 : UseInfo UseInfoForBasePointer(const ElementAccess& access) {
164 363238 : return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
165 : }
166 :
167 350246 : void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
168 2015867 : for (Edge edge : node->use_edges()) {
169 832849 : if (NodeProperties::IsControlEdge(edge)) {
170 0 : edge.UpdateTo(control);
171 832805 : } else if (NodeProperties::IsEffectEdge(edge)) {
172 422445 : edge.UpdateTo(effect);
173 : } else {
174 : DCHECK(NodeProperties::IsValueEdge(edge) ||
175 : NodeProperties::IsContextEdge(edge));
176 : }
177 : }
178 350169 : }
179 :
180 153791 : 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 153791 : left = Type::Intersect(left, Type::Signed32(), type_zone);
186 153777 : right = Type::Intersect(right, Type::Signed32(), type_zone);
187 307510 : if (left.IsNone() || right.IsNone()) return false;
188 153742 : switch (op->opcode()) {
189 : case IrOpcode::kSpeculativeSafeIntegerAdd:
190 149459 : return (left.Max() + right.Max() > kMaxInt) ||
191 4315 : (left.Min() + right.Min() < kMinInt);
192 :
193 : case IrOpcode::kSpeculativeSafeIntegerSubtract:
194 16424 : return (left.Max() - right.Min() > kMaxInt) ||
195 7826 : (left.Min() - right.Max() < kMinInt);
196 :
197 : default:
198 0 : UNREACHABLE();
199 : }
200 : return true;
201 : }
202 :
203 9159 : bool IsSomePositiveOrderedNumber(Type type) {
204 15364 : 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 464180 : class RepresentationSelector {
236 : public:
237 : // Information for each node tracked during the fixpoint.
238 464172 : 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 100134226 : bool AddUse(UseInfo info) {
243 100134226 : Truncation old_truncation = truncation_;
244 100131821 : truncation_ = Truncation::Generalize(truncation_, info.truncation());
245 100131821 : return truncation_ != old_truncation;
246 : }
247 :
248 36513675 : void set_queued() { state_ = kQueued; }
249 67062269 : void set_visited() { state_ = kVisited; }
250 30549356 : void set_pushed() { state_ = kPushed; }
251 43230967 : 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 34848887 : void set_output(MachineRepresentation output) { representation_ = output; }
257 :
258 : MachineRepresentation representation() const { return representation_; }
259 :
260 : // Helpers for feedback typing.
261 21401403 : void set_feedback_type(Type type) { feedback_type_ = type; }
262 : Type feedback_type() const { return feedback_type_; }
263 91213 : void set_weakened() { weakened_ = true; }
264 : bool weakened() const { return weakened_; }
265 30645889 : 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 464172 : 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 464180 : type_cache_(TypeCache::Get()),
300 1856701 : op_typer_(broker, graph_zone()) {
301 464181 : }
302 :
303 : // Forward propagation of types from type feedback.
304 464177 : void RunTypePropagationPhase() {
305 : // Run type propagation.
306 464177 : TRACE("--{Type propagation phase}--\n");
307 464181 : phase_ = RETYPE;
308 : ResetNodeInfoState();
309 :
310 : DCHECK(typing_stack_.empty());
311 927783 : typing_stack_.push({graph()->end(), 0});
312 : GetInfo(graph()->end())->set_pushed();
313 61099594 : 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 255215862 : while (current.input_index < current.node->InputCount()) {
319 : Node* input = current.node->InputAt(current.input_index);
320 : NodeInfo* input_info = GetInfo(input);
321 97058135 : current.input_index++;
322 97058135 : if (input_info->unvisited()) {
323 : input_info->set_pushed();
324 60171586 : typing_stack_.push({input, 0});
325 : pushed_unvisited = true;
326 30085832 : break;
327 : }
328 : }
329 60635628 : if (pushed_unvisited) continue;
330 :
331 : // Process the top of the stack.
332 30549777 : Node* node = current.node;
333 : typing_stack_.pop();
334 : NodeInfo* info = GetInfo(node);
335 : info->set_visited();
336 30549652 : bool updated = UpdateFeedbackType(node);
337 30549371 : TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
338 30549371 : VisitNode(node, info->truncation(), nullptr);
339 30549664 : TRACE(" ==> output ");
340 30549664 : PrintOutputInfo(info);
341 30549635 : TRACE("\n");
342 30550130 : if (updated) {
343 180271100 : for (Node* const user : node->uses()) {
344 80181375 : if (GetInfo(user)->visited()) {
345 : GetInfo(user)->set_queued();
346 : queue_.push(user);
347 : }
348 : }
349 : }
350 : }
351 :
352 : // Process the revisit queue.
353 5479381 : while (!queue_.empty()) {
354 5015205 : Node* node = queue_.front();
355 : queue_.pop();
356 : NodeInfo* info = GetInfo(node);
357 : info->set_visited();
358 5015211 : bool updated = UpdateFeedbackType(node);
359 5015204 : TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
360 5015204 : VisitNode(node, info->truncation(), nullptr);
361 5015225 : TRACE(" ==> output ");
362 5015225 : PrintOutputInfo(info);
363 5015219 : TRACE("\n");
364 5015341 : if (updated) {
365 13111013 : for (Node* const user : node->uses()) {
366 5808937 : if (GetInfo(user)->visited()) {
367 : GetInfo(user)->set_queued();
368 : queue_.push(user);
369 : }
370 : }
371 : }
372 : }
373 464176 : }
374 :
375 : void ResetNodeInfoState() {
376 : // Clean up for the next phase.
377 43695148 : for (NodeInfo& info : info_) {
378 : info.reset_state();
379 : }
380 : }
381 :
382 : Type TypeOf(Node* node) {
383 : Type type = GetInfo(node)->feedback_type();
384 45441168 : return type.IsInvalid() ? NodeProperties::GetType(node) : type;
385 : }
386 :
387 : Type FeedbackTypeOf(Node* node) {
388 : Type type = GetInfo(node)->feedback_type();
389 38186097 : return type.IsInvalid() ? Type::None() : type;
390 : }
391 :
392 801407 : Type TypePhi(Node* node) {
393 : int arity = node->op()->ValueInputCount();
394 : Type type = FeedbackTypeOf(node->InputAt(0));
395 3180503 : for (int i = 1; i < arity; ++i) {
396 1189545 : type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
397 : }
398 801410 : return type;
399 : }
400 :
401 12554 : Type TypeSelect(Node* node) {
402 : return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
403 12554 : FeedbackTypeOf(node->InputAt(2)));
404 : }
405 :
406 35563473 : bool UpdateFeedbackType(Node* node) {
407 35563473 : if (node->op()->ValueOutputCount() == 0) return false;
408 :
409 : NodeInfo* info = GetInfo(node);
410 : Type type = info->feedback_type();
411 25157293 : 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 25157293 : if (node->opcode() != IrOpcode::kPhi) {
417 141886959 : for (int i = 0; i < node->op()->ValueInputCount(); i++) {
418 59612386 : 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 43896865 : if (node->InputCount() > 0) input0_type = FeedbackTypeOf(node->InputAt(0));
428 : Type input1_type;
429 40832163 : if (node->InputCount() > 1) input1_type = FeedbackTypeOf(node->InputAt(1));
430 :
431 24310620 : 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 480845 : 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 1063 : 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 40755 : SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
465 595 : DECLARE_CASE(CheckFloat64Hole)
466 524 : DECLARE_CASE(CheckNumber)
467 1474 : DECLARE_CASE(CheckInternalizedString)
468 18 : DECLARE_CASE(CheckNonEmptyString)
469 1814 : DECLARE_CASE(CheckNonEmptyOneByteString)
470 248 : DECLARE_CASE(CheckNonEmptyTwoByteString)
471 5676 : DECLARE_CASE(CheckString)
472 : #undef DECLARE_CASE
473 :
474 : case IrOpcode::kConvertReceiver:
475 880 : new_type = op_typer_.ConvertReceiver(input0_type);
476 880 : 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 64456 : info->restriction_type(), graph_zone());
486 64456 : break;
487 :
488 : case IrOpcode::kStringConcat:
489 : new_type = op_typer_.StringConcat(input0_type, input1_type,
490 26458 : FeedbackTypeOf(node->InputAt(2)));
491 26458 : break;
492 :
493 : case IrOpcode::kPhi: {
494 801406 : new_type = TypePhi(node);
495 801410 : if (!type.IsInvalid()) {
496 481931 : new_type = Weaken(node, type, new_type);
497 : }
498 : break;
499 : }
500 :
501 : case IrOpcode::kConvertTaggedHoleToUndefined:
502 : new_type = op_typer_.ConvertTaggedHoleToUndefined(
503 2135 : FeedbackTypeOf(node->InputAt(0)));
504 2135 : break;
505 :
506 : case IrOpcode::kTypeGuard: {
507 : new_type = op_typer_.TypeTypeGuard(node->op(),
508 33656 : FeedbackTypeOf(node->InputAt(0)));
509 33656 : break;
510 : }
511 :
512 : case IrOpcode::kSelect: {
513 12554 : new_type = TypeSelect(node);
514 12554 : break;
515 : }
516 :
517 : default:
518 : // Shortcut for operations that we do not handle.
519 22387135 : if (type.IsInvalid()) {
520 : GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
521 19693951 : 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 1923480 : new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());
530 :
531 2885432 : if (!type.IsInvalid() && new_type.Is(type)) return false;
532 : GetInfo(node)->set_feedback_type(new_type);
533 1707452 : 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 481931 : Type Weaken(Node* node, Type previous_type, Type current_type) {
561 : // If the types have nothing to do with integers, return the types.
562 481931 : Type const integer = type_cache_->kInteger;
563 481931 : if (!previous_type.Maybe(integer)) {
564 29768 : return current_type;
565 : }
566 : DCHECK(current_type.Maybe(integer));
567 :
568 452170 : Type current_integer = Type::Intersect(current_type, integer, graph_zone());
569 : DCHECK(!current_integer.IsNone());
570 : Type previous_integer =
571 452167 : 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 452165 : 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 95496 : Type previous = previous_integer.GetRange();
580 95496 : Type current = current_integer.GetRange();
581 186803 : if (current.IsInvalid() || previous.IsInvalid()) {
582 4282 : 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 447882 : graph_zone());
591 : }
592 :
593 : // Backward propagation of truncations.
594 464179 : void RunTruncationPropagationPhase() {
595 : // Run propagation phase to a fixpoint.
596 464179 : TRACE("--{Propagation phase}--\n");
597 464179 : phase_ = PROPAGATE;
598 464179 : EnqueueInitial(jsgraph_->graph()->end());
599 : // Process nodes from the queue until it is empty.
600 63459022 : while (!queue_.empty()) {
601 31497414 : Node* node = queue_.front();
602 : NodeInfo* info = GetInfo(node);
603 : queue_.pop();
604 : info->set_visited();
605 31497406 : TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
606 : info->truncation().description());
607 31497406 : VisitNode(node, info->truncation(), nullptr);
608 : }
609 464181 : }
610 :
611 464179 : void Run(SimplifiedLowering* lowering) {
612 464179 : RunTruncationPropagationPhase();
613 :
614 464181 : RunTypePropagationPhase();
615 :
616 : // Run lowering and change insertion phase.
617 464177 : TRACE("--{Simplified lowering phase}--\n");
618 464182 : phase_ = LOWER;
619 : // Process nodes from the collected {nodes_} vector.
620 31013097 : for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
621 30548919 : Node* node = *i;
622 : NodeInfo* info = GetInfo(node);
623 30548919 : 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 30548919 : source_positions_, source_positions_->GetSourcePosition(node));
627 : NodeOriginTable::Scope origin_scope(node_origins_, "simplified lowering",
628 30548813 : node);
629 30548813 : VisitNode(node, info->truncation(), lowering);
630 : }
631 :
632 : // Perform the final replacements.
633 1724889 : for (NodeVector::iterator i = replacements_.begin();
634 : i != replacements_.end(); ++i) {
635 1260710 : Node* node = *i;
636 1260710 : Node* replacement = *(++i);
637 1260710 : node->ReplaceUses(replacement);
638 1260708 : node->Kill();
639 : // We also need to replace the node in the rest of the vector.
640 186915072 : for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
641 : ++j;
642 185654361 : if (*j == node) *j = replacement;
643 : }
644 : }
645 464179 : }
646 :
647 464179 : void EnqueueInitial(Node* node) {
648 464179 : NodeInfo* info = GetInfo(node);
649 : info->set_queued();
650 464179 : nodes_.push_back(node);
651 : queue_.push(node);
652 464177 : }
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 159122777 : void EnqueueInput(Node* use_node, int index,
658 : UseInfo use_info = UseInfo::None()) {
659 159122777 : Node* node = use_node->InputAt(index);
660 248192207 : 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 100138680 : if (info->unvisited()) {
668 : // First visit of this node.
669 : info->set_queued();
670 30085974 : nodes_.push_back(node);
671 : queue_.push(node);
672 30085801 : TRACE(" initial #%i: ", node->id());
673 30085801 : info->AddUse(use_info);
674 30085387 : PrintTruncation(info->truncation());
675 30085333 : return;
676 : }
677 70052706 : TRACE(" queue #%i?: ", node->id());
678 70052706 : PrintTruncation(info->truncation());
679 70052014 : if (info->AddUse(use_info)) {
680 : // New usage information for the node is available.
681 2350987 : if (!info->queued()) {
682 : queue_.push(node);
683 : info->set_queued();
684 948121 : TRACE(" added: ");
685 : } else {
686 1402868 : TRACE(" inqueue: ");
687 : }
688 2350989 : 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 95414549 : 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 89652 : bool InputCannotBe(Node* node, Type type) {
719 : DCHECK_EQ(1, node->op()->ValueInputCount());
720 89652 : return !GetUpperBound(node->InputAt(0)).Maybe(type);
721 : }
722 :
723 60386 : bool InputIs(Node* node, Type type) {
724 : DCHECK_EQ(1, node->op()->ValueInputCount());
725 120772 : return GetUpperBound(node->InputAt(0)).Is(type);
726 : }
727 :
728 : bool BothInputsAreSigned32(Node* node) {
729 95414 : return BothInputsAre(node, Type::Signed32());
730 : }
731 :
732 : bool BothInputsAreUnsigned32(Node* node) {
733 102539 : return BothInputsAre(node, Type::Unsigned32());
734 : }
735 :
736 1038258 : bool BothInputsAre(Node* node, Type type) {
737 : DCHECK_EQ(2, node->op()->ValueInputCount());
738 2383907 : return GetUpperBound(node->InputAt(0)).Is(type) &&
739 1345649 : 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 333234 : void ChangeToPureOp(Node* node, const Operator* new_op) {
754 : DCHECK(new_op->HasProperty(Operator::kPure));
755 333234 : if (node->op()->EffectInputCount() > 0) {
756 : DCHECK_LT(0, node->op()->ControlInputCount());
757 210059 : Node* control = NodeProperties::GetControlInput(node);
758 210039 : Node* effect = NodeProperties::GetEffectInput(node);
759 210026 : 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 320 : Node* unreachable = effect = graph()->NewNode(
765 320 : jsgraph_->common()->Unreachable(), effect, control);
766 320 : new_op = jsgraph_->common()->DeadValue(GetInfo(node)->representation());
767 320 : node->ReplaceInput(0, unreachable);
768 : }
769 : // Rewire the effect and control chains.
770 210026 : node->TrimInputCount(new_op->ValueInputCount());
771 210033 : ReplaceEffectControlUses(node, effect, control);
772 : } else {
773 : DCHECK_EQ(0, node->op()->ControlInputCount());
774 : }
775 333203 : NodeProperties::ChangeOp(node, new_op);
776 333186 : }
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 53264108 : 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 53264108 : 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 50808394 : if (input_rep != use.representation() ||
791 : use.type_check() != TypeCheckKind::kNone) {
792 : // Output representation doesn't match usage.
793 16065260 : TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
794 : index, input->id(), input->op()->mnemonic());
795 16065242 : TRACE(" from ");
796 16065242 : PrintOutputInfo(input_info);
797 16065175 : TRACE(" to ");
798 16065175 : PrintUseInfo(use);
799 16065142 : TRACE("\n");
800 16065154 : if (input_type.IsInvalid()) {
801 : input_type = TypeOf(input);
802 : }
803 16065154 : Node* n = changer_->GetRepresentationFor(
804 16065154 : input, input_info->representation(), input_type, node, use);
805 16065002 : node->ReplaceInput(index, n);
806 : }
807 : }
808 :
809 172064204 : void ProcessInput(Node* node, int index, UseInfo use) {
810 172064204 : switch (phase_) {
811 : case PROPAGATE:
812 55121844 : EnqueueInput(node, index, use);
813 55119824 : break;
814 : case RETYPE:
815 : break;
816 : case LOWER:
817 53241653 : ConvertInput(node, index, use);
818 53240489 : break;
819 : }
820 172061020 : }
821 :
822 18403228 : void ProcessRemainingInputs(Node* node, int index) {
823 : DCHECK_GE(index, NodeProperties::PastValueIndex(node));
824 : DCHECK_GE(index, NodeProperties::PastContextIndex(node));
825 78879641 : for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
826 30238236 : i < NodeProperties::PastEffectIndex(node); ++i) {
827 11835056 : EnqueueInput(node, i); // Effect inputs: just visit
828 : }
829 79007280 : for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
830 30302055 : i < NodeProperties::PastControlIndex(node); ++i) {
831 11898893 : EnqueueInput(node, i); // Control inputs: just visit
832 : }
833 18403212 : }
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 29700673 : void VisitInputs(Node* node) {
840 29700417 : int tagged_count = node->op()->ValueInputCount() +
841 : OperatorProperties::GetContextInputCount(node->op()) +
842 29699960 : OperatorProperties::GetFrameStateInputCount(node->op());
843 : // Visit value, context and frame state inputs as tagged.
844 116231532 : for (int i = 0; i < tagged_count; i++) {
845 43265899 : ProcessInput(node, i, UseInfo::AnyTagged());
846 : }
847 : // Only enqueue other inputs (effects, control).
848 141717123 : for (int i = tagged_count; i < node->InputCount(); i++) {
849 56008868 : EnqueueInput(node, i);
850 : }
851 29701129 : }
852 :
853 1671274 : void VisitReturn(Node* node) {
854 1671275 : int tagged_limit = node->op()->ValueInputCount() +
855 : OperatorProperties::GetContextInputCount(node->op()) +
856 1671275 : OperatorProperties::GetFrameStateInputCount(node->op());
857 : // Visit integer slot count to pop
858 1671281 : ProcessInput(node, 0, UseInfo::TruncatingWord32());
859 :
860 : // Visit value, context and frame state inputs as tagged.
861 5013849 : for (int i = 1; i < tagged_limit; i++) {
862 1671285 : ProcessInput(node, i, UseInfo::AnyTagged());
863 : }
864 : // Only enqueue other inputs (effects, control).
865 8356395 : for (int i = tagged_limit; i < node->InputCount(); i++) {
866 3342561 : EnqueueInput(node, i);
867 : }
868 1671284 : }
869 :
870 : // Helper for an unused node.
871 330162 : void VisitUnused(Node* node) {
872 330162 : int value_count = node->op()->ValueInputCount() +
873 : OperatorProperties::GetContextInputCount(node->op()) +
874 330163 : OperatorProperties::GetFrameStateInputCount(node->op());
875 1373051 : for (int i = 0; i < value_count; i++) {
876 521445 : ProcessInput(node, i, UseInfo::None());
877 : }
878 330164 : ProcessRemainingInputs(node, value_count);
879 330162 : if (lower()) Kill(node);
880 330162 : }
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 3507388 : 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 3507388 : ProcessInput(node, 0, left_use);
897 3506737 : ProcessInput(node, 1, right_use);
898 10174697 : for (int i = 2; i < node->InputCount(); i++) {
899 3334135 : EnqueueInput(node, i);
900 : }
901 : SetOutput(node, output, restriction_type);
902 3507257 : }
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 2864312 : VisitBinop(node, input_use, input_use, output, restriction_type);
908 : }
909 :
910 81805 : void VisitSpeculativeInt32Binop(Node* node) {
911 : DCHECK_EQ(2, node->op()->ValueInputCount());
912 81805 : if (BothInputsAre(node, Type::NumberOrOddball())) {
913 : return VisitBinop(node, UseInfo::TruncatingWord32(),
914 : MachineRepresentation::kWord32);
915 : }
916 18503 : NumberOperationHint hint = NumberOperationHintOf(node->op());
917 37006 : return VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
918 18503 : MachineRepresentation::kWord32);
919 : }
920 :
921 : // Helper for unops of the I -> O variety.
922 10715468 : void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output,
923 : Type restriction_type = Type::Any()) {
924 : DCHECK_EQ(1, node->op()->ValueInputCount());
925 10715468 : ProcessInput(node, 0, input_use);
926 10715463 : ProcessRemainingInputs(node, 1);
927 : SetOutput(node, output, restriction_type);
928 10715453 : }
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 630848 : void VisitFloat64Binop(Node* node) {
938 : VisitBinop(node, UseInfo::TruncatingFloat64(),
939 : MachineRepresentation::kFloat64);
940 630863 : }
941 2219 : void VisitInt64Binop(Node* node) {
942 : VisitBinop(node, UseInfo::Word64(), MachineRepresentation::kWord64);
943 2219 : }
944 487901 : void VisitWord32TruncatingBinop(Node* node) {
945 : VisitBinop(node, UseInfo::TruncatingWord32(),
946 : MachineRepresentation::kWord32);
947 487954 : }
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 1651603 : MachineRepresentation GetOutputInfoForPhi(Node* node, Type type,
954 : Truncation use) {
955 : // Compute the representation.
956 1651561 : if (type.Is(Type::None())) {
957 : return MachineRepresentation::kNone;
958 2947794 : } else if (type.Is(Type::Signed32()) || type.Is(Type::Unsigned32())) {
959 : return MachineRepresentation::kWord32;
960 2128891 : } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
961 : return MachineRepresentation::kWord32;
962 1300588 : } else if (type.Is(Type::Boolean())) {
963 : return MachineRepresentation::kBit;
964 1948096 : } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsFloat64()) {
965 : return MachineRepresentation::kFloat64;
966 2290086 : } 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 1144897 : } else if (type.Is(Type::Number())) {
973 : return MachineRepresentation::kFloat64;
974 493477 : } else if (type.Is(Type::ExternalPointer())) {
975 : return MachineType::PointerRepresentation();
976 : }
977 493477 : return MachineRepresentation::kTagged;
978 : }
979 :
980 : // Helper for handling selects.
981 38621 : void VisitSelect(Node* node, Truncation truncation,
982 : SimplifiedLowering* lowering) {
983 : DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
984 38621 : ProcessInput(node, 0, UseInfo::Bool());
985 :
986 : MachineRepresentation output =
987 38621 : GetOutputInfoForPhi(node, TypeOf(node), truncation);
988 : SetOutput(node, output);
989 :
990 38621 : if (lower()) {
991 : // Update the select operator.
992 12554 : SelectParameters p = SelectParametersOf(node->op());
993 12554 : if (output != p.representation()) {
994 7263 : NodeProperties::ChangeOp(node,
995 7263 : 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 77242 : UseInfo input_use(output, truncation);
1001 38621 : ProcessInput(node, 1, input_use);
1002 38621 : ProcessInput(node, 2, input_use);
1003 38621 : }
1004 :
1005 : // Helper for handling phis.
1006 1521403 : void VisitPhi(Node* node, Truncation truncation,
1007 : SimplifiedLowering* lowering) {
1008 : MachineRepresentation output =
1009 1521403 : 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 1521335 : if (lower()) {
1016 : // Update the phi operator.
1017 319481 : if (output != PhiRepresentationOf(node->op())) {
1018 176480 : 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 3043126 : UseInfo input_use(output, truncation);
1025 12765020 : for (int i = 0; i < node->InputCount(); i++) {
1026 11243860 : ProcessInput(node, i, i < values ? input_use : UseInfo::None());
1027 : }
1028 1521456 : }
1029 :
1030 162521 : void VisitObjectIs(Node* node, Type type, SimplifiedLowering* lowering) {
1031 162521 : Type const input_type = TypeOf(node->InputAt(0));
1032 162521 : if (input_type.Is(type)) {
1033 4041 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
1034 4041 : if (lower()) {
1035 1379 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
1036 : }
1037 : } else {
1038 158481 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
1039 158481 : if (lower() && !input_type.Maybe(type)) {
1040 485 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1041 : }
1042 : }
1043 162522 : }
1044 :
1045 15458 : void VisitCheck(Node* node, Type type, SimplifiedLowering* lowering) {
1046 15458 : if (InputIs(node, type)) {
1047 : VisitUnop(node, UseInfo::AnyTagged(),
1048 1189 : MachineRepresentation::kTaggedPointer);
1049 1559 : if (lower()) DeferReplacement(node, node->InputAt(0));
1050 : } else {
1051 28538 : VisitUnop(node,
1052 : UseInfo::CheckedHeapObjectAsTaggedPointer(VectorSlotPair()),
1053 14269 : MachineRepresentation::kTaggedPointer);
1054 : }
1055 15458 : }
1056 :
1057 338180 : void VisitCall(Node* node, SimplifiedLowering* lowering) {
1058 338180 : auto call_descriptor = CallDescriptorOf(node->op());
1059 338183 : int params = static_cast<int>(call_descriptor->ParameterCount());
1060 : int value_input_count = node->op()->ValueInputCount();
1061 : // Propagate representation information from call descriptor.
1062 5136335 : for (int i = 0; i < value_input_count; i++) {
1063 2399076 : if (i == 0) {
1064 : // The target of the call.
1065 338180 : ProcessInput(node, i, UseInfo::Any());
1066 2060896 : } else if ((i - 1) < params) {
1067 1727685 : ProcessInput(node, i,
1068 : TruncatingUseInfoFromRepresentation(
1069 3455369 : call_descriptor->GetInputType(i).representation()));
1070 : } else {
1071 333210 : ProcessInput(node, i, UseInfo::AnyTagged());
1072 : }
1073 : }
1074 338183 : ProcessRemainingInputs(node, value_input_count);
1075 :
1076 338181 : if (call_descriptor->ReturnCount() > 0) {
1077 : SetOutput(node, call_descriptor->GetReturnType(0).representation());
1078 : } else {
1079 : SetOutput(node, MachineRepresentation::kTagged);
1080 : }
1081 338181 : }
1082 :
1083 10052 : void MaskShiftOperand(Node* node, Type rhs_type) {
1084 20105 : if (!rhs_type.Is(type_cache_->kZeroToThirtyOne)) {
1085 959 : Node* const rhs = NodeProperties::GetValueInput(node, 1);
1086 1918 : node->ReplaceInput(1,
1087 959 : graph()->NewNode(jsgraph_->machine()->Word32And(), rhs,
1088 1918 : jsgraph_->Int32Constant(0x1F)));
1089 : }
1090 10053 : }
1091 :
1092 531686 : static MachineSemantic DeoptValueSemanticOf(Type type) {
1093 : // We only need signedness to do deopt correctly.
1094 531665 : if (type.Is(Type::Signed32())) {
1095 : return MachineSemantic::kInt32;
1096 362611 : } else if (type.Is(Type::Unsigned32())) {
1097 : return MachineSemantic::kUint32;
1098 : } else {
1099 361000 : return MachineSemantic::kAny;
1100 : }
1101 : }
1102 :
1103 11294644 : static MachineType DeoptMachineTypeOf(MachineRepresentation rep, Type type) {
1104 11294644 : if (type.IsNone()) {
1105 : return MachineType::None();
1106 : }
1107 : // Do not distinguish between various Tagged variations.
1108 11294644 : if (IsAnyTagged(rep)) {
1109 : return MachineType::AnyTagged();
1110 : }
1111 : // Word64 representation is only valid for safe integer values.
1112 531736 : if (rep == MachineRepresentation::kWord64) {
1113 : DCHECK(type.Is(TypeCache::Get()->kSafeInteger));
1114 51 : return MachineType(rep, MachineSemantic::kInt64);
1115 : }
1116 531685 : MachineType machine_type(rep, DeoptValueSemanticOf(type));
1117 : DCHECK(machine_type.representation() != MachineRepresentation::kWord32 ||
1118 : machine_type.semantic() == MachineSemantic::kInt32 ||
1119 : machine_type.semantic() == MachineSemantic::kUint32);
1120 : DCHECK(machine_type.representation() != MachineRepresentation::kBit ||
1121 : type.Is(Type::Boolean()));
1122 531675 : return machine_type;
1123 : }
1124 :
1125 10996347 : void VisitStateValues(Node* node) {
1126 10996347 : if (propagate()) {
1127 23712071 : for (int i = 0; i < node->InputCount(); i++) {
1128 10297635 : EnqueueInput(node, i, UseInfo::Any());
1129 : }
1130 7879420 : } else if (lower()) {
1131 3117018 : Zone* zone = jsgraph_->zone();
1132 : ZoneVector<MachineType>* types =
1133 : new (zone->New(sizeof(ZoneVector<MachineType>)))
1134 6234046 : ZoneVector<MachineType>(node->InputCount(), zone);
1135 23712243 : for (int i = 0; i < node->InputCount(); i++) {
1136 : Node* input = node->InputAt(i);
1137 10297621 : (*types)[i] =
1138 10297621 : DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1139 : }
1140 3117013 : SparseInputMask mask = SparseInputMaskOf(node->op());
1141 3117013 : NodeProperties::ChangeOp(
1142 6234021 : node, jsgraph_->common()->TypedStateValues(types, mask));
1143 : }
1144 : SetOutput(node, MachineRepresentation::kTagged);
1145 10996356 : }
1146 :
1147 16622414 : void VisitFrameState(Node* node) {
1148 : DCHECK_EQ(5, node->op()->ValueInputCount());
1149 : DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
1150 :
1151 16622490 : ProcessInput(node, 0, UseInfo::AnyTagged()); // Parameters.
1152 16622490 : ProcessInput(node, 1, UseInfo::AnyTagged()); // Registers.
1153 :
1154 : // Accumulator is a special flower - we need to remember its type in
1155 : // a singleton typed-state-values node (as if it was a singleton
1156 : // state-values node).
1157 16622506 : if (propagate()) {
1158 5259990 : EnqueueInput(node, 2, UseInfo::Any());
1159 11362527 : } else if (lower()) {
1160 5259978 : Zone* zone = jsgraph_->zone();
1161 : Node* accumulator = node->InputAt(2);
1162 5259978 : if (accumulator == jsgraph_->OptimizedOutConstant()) {
1163 4396400 : node->ReplaceInput(2, jsgraph_->SingleDeadTypedStateValues());
1164 : } else {
1165 : ZoneVector<MachineType>* types =
1166 : new (zone->New(sizeof(ZoneVector<MachineType>)))
1167 863579 : ZoneVector<MachineType>(1, zone);
1168 : (*types)[0] = DeoptMachineTypeOf(GetInfo(accumulator)->representation(),
1169 863578 : TypeOf(accumulator));
1170 :
1171 863578 : node->ReplaceInput(
1172 1727155 : 2, jsgraph_->graph()->NewNode(jsgraph_->common()->TypedStateValues(
1173 : types, SparseInputMask::Dense()),
1174 863577 : accumulator));
1175 : }
1176 : }
1177 :
1178 16622536 : ProcessInput(node, 3, UseInfo::AnyTagged()); // Context.
1179 16622511 : ProcessInput(node, 4, UseInfo::AnyTagged()); // Closure.
1180 16622498 : ProcessInput(node, 5, UseInfo::AnyTagged()); // Outer frame state.
1181 16622478 : return SetOutput(node, MachineRepresentation::kTagged);
1182 : }
1183 :
1184 69405 : void VisitObjectState(Node* node) {
1185 69405 : if (propagate()) {
1186 289189 : for (int i = 0; i < node->InputCount(); i++) {
1187 133367 : EnqueueInput(node, i, UseInfo::Any());
1188 : }
1189 46950 : } else if (lower()) {
1190 22455 : Zone* zone = jsgraph_->zone();
1191 : ZoneVector<MachineType>* types =
1192 : new (zone->New(sizeof(ZoneVector<MachineType>)))
1193 44910 : ZoneVector<MachineType>(node->InputCount(), zone);
1194 289189 : for (int i = 0; i < node->InputCount(); i++) {
1195 : Node* input = node->InputAt(i);
1196 133367 : (*types)[i] =
1197 133367 : DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1198 : }
1199 22455 : NodeProperties::ChangeOp(node, jsgraph_->common()->TypedObjectState(
1200 22455 : ObjectIdOf(node->op()), types));
1201 : }
1202 : SetOutput(node, MachineRepresentation::kTagged);
1203 69405 : }
1204 :
1205 : const Operator* Int32Op(Node* node) {
1206 212287 : return changer_->Int32OperatorFor(node->opcode());
1207 : }
1208 :
1209 : const Operator* Int32OverflowOp(Node* node) {
1210 150129 : return changer_->Int32OverflowOperatorFor(node->opcode());
1211 : }
1212 :
1213 : const Operator* Int64Op(Node* node) {
1214 525 : return changer_->Int64OperatorFor(node->opcode());
1215 : }
1216 :
1217 : const Operator* Uint32Op(Node* node) {
1218 36345 : return changer_->Uint32OperatorFor(node->opcode());
1219 : }
1220 :
1221 : const Operator* Uint32OverflowOp(Node* node) {
1222 113 : return changer_->Uint32OverflowOperatorFor(node->opcode());
1223 : }
1224 :
1225 : const Operator* Float64Op(Node* node) {
1226 167915 : return changer_->Float64OperatorFor(node->opcode());
1227 : }
1228 :
1229 6395402 : WriteBarrierKind WriteBarrierKindFor(
1230 : BaseTaggedness base_taggedness,
1231 : MachineRepresentation field_representation, Type field_type,
1232 : MachineRepresentation value_representation, Node* value) {
1233 12790804 : if (base_taggedness == kTaggedBase &&
1234 : CanBeTaggedPointer(field_representation)) {
1235 5605806 : Type value_type = NodeProperties::GetType(value);
1236 11211612 : if (field_representation == MachineRepresentation::kTaggedSigned ||
1237 5605806 : value_representation == MachineRepresentation::kTaggedSigned) {
1238 : // Write barriers are only for stores of heap objects.
1239 : return kNoWriteBarrier;
1240 : }
1241 11211613 : if (field_type.Is(Type::BooleanOrNullOrUndefined()) ||
1242 : value_type.Is(Type::BooleanOrNullOrUndefined())) {
1243 : // Write barriers are not necessary when storing true, false, null or
1244 : // undefined, because these special oddballs are always in the root set.
1245 : return kNoWriteBarrier;
1246 : }
1247 5223075 : if (value_type.IsHeapConstant()) {
1248 : RootIndex root_index;
1249 1886987 : const RootsTable& roots_table = jsgraph_->isolate()->roots_table();
1250 3773973 : if (roots_table.IsRootHandle(value_type.AsHeapConstant()->Value(),
1251 : &root_index)) {
1252 1082032 : if (RootsTable::IsImmortalImmovable(root_index)) {
1253 : // Write barriers are unnecessary for immortal immovable roots.
1254 : return kNoWriteBarrier;
1255 : }
1256 : }
1257 : }
1258 8282086 : if (field_representation == MachineRepresentation::kTaggedPointer ||
1259 4141043 : value_representation == MachineRepresentation::kTaggedPointer) {
1260 : // Write barriers for heap objects are cheaper.
1261 : return kPointerWriteBarrier;
1262 : }
1263 : NumberMatcher m(value);
1264 3196511 : if (m.HasValue()) {
1265 1589 : if (IsSmiDouble(m.Value())) {
1266 : // Storing a smi doesn't need a write barrier.
1267 : return kNoWriteBarrier;
1268 : }
1269 : // The NumberConstant will be represented as HeapNumber.
1270 1589 : return kPointerWriteBarrier;
1271 : }
1272 : return kFullWriteBarrier;
1273 : }
1274 : return kNoWriteBarrier;
1275 : }
1276 :
1277 : WriteBarrierKind WriteBarrierKindFor(
1278 : BaseTaggedness base_taggedness,
1279 : MachineRepresentation field_representation, int field_offset,
1280 : Type field_type, MachineRepresentation value_representation,
1281 : Node* value) {
1282 : WriteBarrierKind write_barrier_kind =
1283 6276196 : WriteBarrierKindFor(base_taggedness, field_representation, field_type,
1284 6276196 : value_representation, value);
1285 6276194 : if (write_barrier_kind != kNoWriteBarrier) {
1286 8192652 : if (base_taggedness == kTaggedBase &&
1287 4096326 : field_offset == HeapObject::kMapOffset) {
1288 : write_barrier_kind = kMapWriteBarrier;
1289 : }
1290 : }
1291 : return write_barrier_kind;
1292 : }
1293 :
1294 : Graph* graph() const { return jsgraph_->graph(); }
1295 : CommonOperatorBuilder* common() const { return jsgraph_->common(); }
1296 : SimplifiedOperatorBuilder* simplified() const {
1297 : return jsgraph_->simplified();
1298 : }
1299 :
1300 6246 : void LowerToCheckedInt32Mul(Node* node, Truncation truncation,
1301 : Type input0_type, Type input1_type) {
1302 : // If one of the inputs is positive and/or truncation is being applied,
1303 : // there is no need to return -0.
1304 : CheckForMinusZeroMode mz_mode =
1305 4600 : truncation.IdentifiesZeroAndMinusZero() ||
1306 9159 : IsSomePositiveOrderedNumber(input0_type) ||
1307 4559 : IsSomePositiveOrderedNumber(input1_type)
1308 : ? CheckForMinusZeroMode::kDontCheckForMinusZero
1309 6246 : : CheckForMinusZeroMode::kCheckForMinusZero;
1310 :
1311 6246 : NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
1312 6246 : }
1313 :
1314 150129 : void ChangeToInt32OverflowOp(Node* node) {
1315 150123 : NodeProperties::ChangeOp(node, Int32OverflowOp(node));
1316 150108 : }
1317 :
1318 113 : void ChangeToUint32OverflowOp(Node* node) {
1319 113 : NodeProperties::ChangeOp(node, Uint32OverflowOp(node));
1320 113 : }
1321 :
1322 790016 : void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation,
1323 : SimplifiedLowering* lowering) {
1324 790016 : Type left_upper = GetUpperBound(node->InputAt(0));
1325 790016 : Type right_upper = GetUpperBound(node->InputAt(1));
1326 :
1327 1927261 : if (left_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1328 347254 : right_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero)) {
1329 : // Only eliminate the node if its typing rule can be satisfied, namely
1330 : // that a safe integer is produced.
1331 341274 : if (truncation.IsUnused()) return VisitUnused(node);
1332 :
1333 : // If we know how to interpret the result or if the users only care
1334 : // about the low 32-bits, we can truncate to Word32 do a wrapping
1335 : // addition.
1336 715672 : if (GetUpperBound(node).Is(Type::Signed32()) ||
1337 391594 : GetUpperBound(node).Is(Type::Unsigned32()) ||
1338 : truncation.IsUsedAsWord32()) {
1339 : // => Int32Add/Sub
1340 260168 : VisitWord32TruncatingBinop(node);
1341 323490 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1342 : return;
1343 : }
1344 : }
1345 :
1346 : // Try to use type feedback.
1347 512418 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1348 : DCHECK(hint == NumberOperationHint::kSignedSmall ||
1349 : hint == NumberOperationHint::kSigned32);
1350 :
1351 512702 : Type left_feedback_type = TypeOf(node->InputAt(0));
1352 512702 : Type right_feedback_type = TypeOf(node->InputAt(1));
1353 : // Handle the case when no int32 checks on inputs are necessary (but
1354 : // an overflow check is needed on the output). Note that we do not
1355 : // have to do any check if at most one side can be minus zero. For
1356 : // subtraction we need to handle the case of -0 - 0 properly, since
1357 : // that can produce -0.
1358 : Type left_constraint_type =
1359 : node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd
1360 : ? Type::Signed32OrMinusZero()
1361 512702 : : Type::Signed32();
1362 580277 : if (left_upper.Is(left_constraint_type) &&
1363 574174 : right_upper.Is(Type::Signed32OrMinusZero()) &&
1364 21 : (left_upper.Is(Type::Signed32()) || right_upper.Is(Type::Signed32()))) {
1365 : VisitBinop(node, UseInfo::TruncatingWord32(),
1366 : MachineRepresentation::kWord32, Type::Signed32());
1367 : } else {
1368 : // If the output's truncation is identify-zeros, we can pass it
1369 : // along. Moreover, if the operation is addition and we know the
1370 : // right-hand side is not minus zero, we do not have to distinguish
1371 : // between 0 and -0.
1372 : IdentifyZeros left_identify_zeros = truncation.identify_zeros();
1373 887439 : if (node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd &&
1374 436232 : !right_feedback_type.Maybe(Type::MinusZero())) {
1375 : left_identify_zeros = kIdentifyZeros;
1376 : }
1377 : UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
1378 451207 : left_identify_zeros);
1379 : // For CheckedInt32Add and CheckedInt32Sub, we don't need to do
1380 : // a minus zero check for the right hand side, since we already
1381 : // know that the left hand side is a proper Signed32 value,
1382 : // potentially guarded by a check.
1383 : UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
1384 451393 : kIdentifyZeros);
1385 : VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32,
1386 451373 : Type::Signed32());
1387 : }
1388 512913 : if (lower()) {
1389 308135 : if (truncation.IsUsedAsWord32() ||
1390 153794 : !CanOverflowSigned32(node->op(), left_feedback_type,
1391 : right_feedback_type, graph_zone())) {
1392 5748 : ChangeToPureOp(node, Int32Op(node));
1393 :
1394 : } else {
1395 148593 : ChangeToInt32OverflowOp(node);
1396 : }
1397 : }
1398 : return;
1399 : }
1400 :
1401 3887 : void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
1402 : SimplifiedLowering* lowering) {
1403 11661 : if (BothInputsAre(node, type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1404 3887 : (GetUpperBound(node).Is(Type::Signed32()) ||
1405 0 : GetUpperBound(node).Is(Type::Unsigned32()) ||
1406 : truncation.IsUsedAsWord32())) {
1407 : // => Int32Add/Sub
1408 0 : VisitWord32TruncatingBinop(node);
1409 0 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1410 : return;
1411 : }
1412 :
1413 : // default case => Float64Add/Sub
1414 7774 : VisitBinop(node,
1415 : UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1416 : VectorSlotPair()),
1417 : MachineRepresentation::kFloat64, Type::Number());
1418 3887 : if (lower()) {
1419 1112 : ChangeToPureOp(node, Float64Op(node));
1420 : }
1421 : return;
1422 : }
1423 :
1424 13904 : void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
1425 : SimplifiedLowering* lowering) {
1426 42319 : if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1427 165 : (truncation.IsUsedAsWord32() ||
1428 14234 : NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1429 : // => unsigned Uint32Mod
1430 640 : VisitWord32TruncatingBinop(node);
1431 640 : if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1432 : return;
1433 : }
1434 46797 : if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1435 1236 : (truncation.IsUsedAsWord32() ||
1436 15736 : NodeProperties::GetType(node).Is(Type::Signed32()))) {
1437 : // => signed Int32Mod
1438 7005 : VisitWord32TruncatingBinop(node);
1439 7005 : if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1440 : return;
1441 : }
1442 :
1443 : // Try to use type feedback.
1444 6259 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1445 :
1446 : // Handle the case when no uint32 checks on inputs are necessary
1447 : // (but an overflow check is needed on the output).
1448 6259 : if (BothInputsAreUnsigned32(node)) {
1449 264 : if (hint == NumberOperationHint::kSignedSmall ||
1450 132 : hint == NumberOperationHint::kSigned32) {
1451 : VisitBinop(node, UseInfo::TruncatingWord32(),
1452 : MachineRepresentation::kWord32, Type::Unsigned32());
1453 132 : if (lower()) ChangeToUint32OverflowOp(node);
1454 : return;
1455 : }
1456 : }
1457 :
1458 : // Handle the case when no int32 checks on inputs are necessary
1459 : // (but an overflow check is needed on the output).
1460 6127 : if (BothInputsAre(node, Type::Signed32())) {
1461 : // If both the inputs the feedback are int32, use the overflow op.
1462 2208 : if (hint == NumberOperationHint::kSignedSmall ||
1463 1104 : hint == NumberOperationHint::kSigned32) {
1464 : VisitBinop(node, UseInfo::TruncatingWord32(),
1465 : MachineRepresentation::kWord32, Type::Signed32());
1466 1104 : if (lower()) ChangeToInt32OverflowOp(node);
1467 : return;
1468 : }
1469 : }
1470 :
1471 10046 : if (hint == NumberOperationHint::kSignedSmall ||
1472 5023 : hint == NumberOperationHint::kSigned32) {
1473 : // If the result is truncated, we only need to check the inputs.
1474 : // For the left hand side we just propagate the identify zeros
1475 : // mode of the {truncation}; and for modulus the sign of the
1476 : // right hand side doesn't matter anyways, so in particular there's
1477 : // no observable difference between a 0 and a -0 then.
1478 : UseInfo const lhs_use = CheckedUseInfoAsWord32FromHint(
1479 4213 : hint, VectorSlotPair(), truncation.identify_zeros());
1480 : UseInfo const rhs_use = CheckedUseInfoAsWord32FromHint(
1481 4213 : hint, VectorSlotPair(), kIdentifyZeros);
1482 4213 : if (truncation.IsUsedAsWord32()) {
1483 186 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
1484 186 : if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1485 4027 : } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
1486 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
1487 0 : Type::Unsigned32());
1488 0 : if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1489 : } else {
1490 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
1491 4027 : Type::Signed32());
1492 4027 : if (lower()) ChangeToInt32OverflowOp(node);
1493 : }
1494 : return;
1495 : }
1496 :
1497 1672 : if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
1498 1672 : TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
1499 0 : (truncation.IsUsedAsWord32() ||
1500 810 : NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1501 : VisitBinop(node, UseInfo::TruncatingWord32(),
1502 : MachineRepresentation::kWord32, Type::Number());
1503 0 : if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1504 : return;
1505 : }
1506 1739 : if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
1507 1739 : TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
1508 0 : (truncation.IsUsedAsWord32() ||
1509 810 : NodeProperties::GetType(node).Is(Type::Signed32()))) {
1510 : VisitBinop(node, UseInfo::TruncatingWord32(),
1511 : MachineRepresentation::kWord32, Type::Number());
1512 0 : if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1513 : return;
1514 : }
1515 :
1516 : // default case => Float64Mod
1517 : // For the left hand side we just propagate the identify zeros
1518 : // mode of the {truncation}; and for modulus the sign of the
1519 : // right hand side doesn't matter anyways, so in particular there's
1520 : // no observable difference between a 0 and a -0 then.
1521 : UseInfo const lhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1522 1620 : truncation.identify_zeros(), VectorSlotPair());
1523 : UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1524 1620 : kIdentifyZeros, VectorSlotPair());
1525 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
1526 810 : Type::Number());
1527 1022 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1528 : return;
1529 : }
1530 :
1531 30548283 : void InsertUnreachableIfNecessary(Node* node) {
1532 : DCHECK(lower());
1533 : // If the node is effectful and it produces an impossible value, then we
1534 : // insert Unreachable node after it.
1535 51202532 : if (node->op()->ValueOutputCount() > 0 &&
1536 5460841 : node->op()->EffectOutputCount() > 0 &&
1537 36008354 : node->opcode() != IrOpcode::kUnreachable && TypeOf(node).IsNone()) {
1538 : Node* control =
1539 : (node->op()->ControlOutputCount() == 0)
1540 : ? NodeProperties::GetControlInput(node, 0)
1541 1180 : : NodeProperties::FindSuccessfulControlProjection(node);
1542 :
1543 : Node* unreachable =
1544 1180 : graph()->NewNode(common()->Unreachable(), node, control);
1545 :
1546 : // Insert unreachable node and replace all the effect uses of the {node}
1547 : // with the new unreachable node.
1548 7426 : for (Edge edge : node->use_edges()) {
1549 3123 : if (!NodeProperties::IsEffectEdge(edge)) continue;
1550 : // Make sure to not overwrite the unreachable node's input. That would
1551 : // create a cycle.
1552 2367 : if (edge.from() == unreachable) continue;
1553 : // Avoid messing up the exceptional path.
1554 1187 : if (edge.from()->opcode() == IrOpcode::kIfException) {
1555 : DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
1556 : DCHECK_EQ(NodeProperties::GetControlInput(edge.from()), node);
1557 : continue;
1558 : }
1559 :
1560 1180 : edge.UpdateTo(unreachable);
1561 : }
1562 : }
1563 30548283 : }
1564 :
1565 187567 : void VisitCheckBounds(Node* node, SimplifiedLowering* lowering) {
1566 187567 : CheckParameters const& p = CheckParametersOf(node->op());
1567 187567 : Type const index_type = TypeOf(node->InputAt(0));
1568 187567 : Type const length_type = TypeOf(node->InputAt(1));
1569 187567 : if (length_type.Is(Type::Unsigned31())) {
1570 186946 : if (index_type.Is(Type::Integral32OrMinusZero())) {
1571 : // Map -0 to 0, and the values in the [-2^31,-1] range to the
1572 : // [2^31,2^32-1] range, which will be considered out-of-bounds
1573 : // as well, because the {length_type} is limited to Unsigned31.
1574 : VisitBinop(node, UseInfo::TruncatingWord32(),
1575 : MachineRepresentation::kWord32);
1576 173281 : if (lower()) {
1577 : CheckBoundsParameters::Mode mode =
1578 : CheckBoundsParameters::kDeoptOnOutOfBounds;
1579 104256 : if (lowering->poisoning_level_ ==
1580 104256 : PoisoningMitigationLevel::kDontPoison &&
1581 104256 : (index_type.IsNone() || length_type.IsNone() ||
1582 100349 : (index_type.Min() >= 0.0 &&
1583 48221 : index_type.Max() < length_type.Min()))) {
1584 : // The bounds check is redundant if we already know that
1585 : // the index is within the bounds of [0.0, length[.
1586 : mode = CheckBoundsParameters::kAbortOnOutOfBounds;
1587 : }
1588 52128 : NodeProperties::ChangeOp(
1589 52128 : node, simplified()->CheckedUint32Bounds(p.feedback(), mode));
1590 : }
1591 : } else {
1592 : VisitBinop(
1593 : node,
1594 : UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, p.feedback()),
1595 13665 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1596 13665 : if (lower()) {
1597 2605 : NodeProperties::ChangeOp(
1598 : node,
1599 : simplified()->CheckedUint32Bounds(
1600 2605 : p.feedback(), CheckBoundsParameters::kDeoptOnOutOfBounds));
1601 : }
1602 : }
1603 : } else {
1604 : DCHECK(length_type.Is(type_cache_->kPositiveSafeInteger));
1605 : VisitBinop(node,
1606 : UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, p.feedback()),
1607 622 : UseInfo::Word64(), MachineRepresentation::kWord64);
1608 622 : if (lower()) {
1609 202 : NodeProperties::ChangeOp(
1610 202 : node, simplified()->CheckedUint64Bounds(p.feedback()));
1611 : }
1612 : }
1613 187568 : }
1614 :
1615 : // Dispatching routine for visiting the node {node} with the usage {use}.
1616 : // Depending on the operator, propagate new usage info to the inputs.
1617 97599164 : void VisitNode(Node* node, Truncation truncation,
1618 : SimplifiedLowering* lowering) {
1619 : // Unconditionally eliminate unused pure nodes (only relevant if there's
1620 : // a pure operation in between two effectful ones, where the last one
1621 : // is unused).
1622 : // Note: We must not do this for constants, as they are cached and we
1623 : // would thus kill the cached {node} during lowering (i.e. replace all
1624 : // uses with Dead), but at that point some node lowering might have
1625 : // already taken the constant {node} from the cache (while it was in
1626 : // a sane state still) and we would afterwards replace that use with
1627 : // Dead as well.
1628 158324440 : if (node->op()->ValueInputCount() > 0 &&
1629 134492746 : node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) {
1630 109255 : return VisitUnused(node);
1631 : }
1632 :
1633 97489909 : if (lower()) InsertUnreachableIfNecessary(node);
1634 :
1635 97503567 : switch (node->opcode()) {
1636 : //------------------------------------------------------------------
1637 : // Common operators.
1638 : //------------------------------------------------------------------
1639 : case IrOpcode::kStart:
1640 : // We use Start as a terminator for the frame state chain, so even
1641 : // tho Start doesn't really produce a value, we have to say Tagged
1642 : // here, otherwise the input conversion will fail.
1643 : return VisitLeaf(node, MachineRepresentation::kTagged);
1644 : case IrOpcode::kParameter:
1645 : // TODO(titzer): use representation from linkage.
1646 6004118 : return VisitUnop(node, UseInfo::None(), MachineRepresentation::kTagged);
1647 : case IrOpcode::kInt32Constant:
1648 : return VisitLeaf(node, MachineRepresentation::kWord32);
1649 : case IrOpcode::kInt64Constant:
1650 : return VisitLeaf(node, MachineRepresentation::kWord64);
1651 : case IrOpcode::kExternalConstant:
1652 : return VisitLeaf(node, MachineType::PointerRepresentation());
1653 : case IrOpcode::kNumberConstant: {
1654 3569698 : double const value = OpParameter<double>(node->op());
1655 : int value_as_int;
1656 3569698 : if (DoubleToSmiInteger(value, &value_as_int)) {
1657 : VisitLeaf(node, MachineRepresentation::kTaggedSigned);
1658 3426951 : if (lower()) {
1659 : intptr_t smi = bit_cast<intptr_t>(Smi::FromInt(value_as_int));
1660 1098085 : DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(smi));
1661 : }
1662 : return;
1663 : }
1664 : VisitLeaf(node, MachineRepresentation::kTagged);
1665 : return;
1666 : }
1667 : case IrOpcode::kHeapConstant:
1668 : case IrOpcode::kDelayedStringConstant:
1669 : return VisitLeaf(node, MachineRepresentation::kTaggedPointer);
1670 : case IrOpcode::kPointerConstant: {
1671 : VisitLeaf(node, MachineType::PointerRepresentation());
1672 666 : if (lower()) {
1673 222 : intptr_t const value = OpParameter<intptr_t>(node->op());
1674 222 : DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
1675 : }
1676 : return;
1677 : }
1678 :
1679 : case IrOpcode::kBranch: {
1680 : DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
1681 1846288 : ProcessInput(node, 0, UseInfo::Bool());
1682 1846222 : EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1683 1846212 : return;
1684 : }
1685 : case IrOpcode::kSwitch:
1686 18983 : ProcessInput(node, 0, UseInfo::TruncatingWord32());
1687 18983 : EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1688 18983 : return;
1689 : case IrOpcode::kSelect:
1690 38621 : return VisitSelect(node, truncation, lowering);
1691 : case IrOpcode::kPhi:
1692 1521410 : return VisitPhi(node, truncation, lowering);
1693 : case IrOpcode::kCall:
1694 338180 : return VisitCall(node, lowering);
1695 :
1696 : //------------------------------------------------------------------
1697 : // JavaScript operators.
1698 : //------------------------------------------------------------------
1699 : case IrOpcode::kToBoolean: {
1700 153463 : if (truncation.IsUsedAsBool()) {
1701 152860 : ProcessInput(node, 0, UseInfo::Bool());
1702 : SetOutput(node, MachineRepresentation::kBit);
1703 201302 : if (lower()) DeferReplacement(node, node->InputAt(0));
1704 : } else {
1705 603 : VisitInputs(node);
1706 : SetOutput(node, MachineRepresentation::kTaggedPointer);
1707 : }
1708 : return;
1709 : }
1710 : case IrOpcode::kJSToNumber:
1711 : case IrOpcode::kJSToNumberConvertBigInt:
1712 : case IrOpcode::kJSToNumeric: {
1713 38181 : VisitInputs(node);
1714 : // TODO(bmeurer): Optimize somewhat based on input type?
1715 38181 : if (truncation.IsUsedAsWord32()) {
1716 : SetOutput(node, MachineRepresentation::kWord32);
1717 333 : if (lower())
1718 75 : lowering->DoJSToNumberOrNumericTruncatesToWord32(node, this);
1719 37848 : } else if (truncation.IsUsedAsFloat64()) {
1720 : SetOutput(node, MachineRepresentation::kFloat64);
1721 4987 : if (lower())
1722 1413 : lowering->DoJSToNumberOrNumericTruncatesToFloat64(node, this);
1723 : } else {
1724 : SetOutput(node, MachineRepresentation::kTagged);
1725 : }
1726 : return;
1727 : }
1728 :
1729 : //------------------------------------------------------------------
1730 : // Simplified operators.
1731 : //------------------------------------------------------------------
1732 : case IrOpcode::kBooleanNot: {
1733 9679 : if (lower()) {
1734 : NodeInfo* input_info = GetInfo(node->InputAt(0));
1735 3111 : if (input_info->representation() == MachineRepresentation::kBit) {
1736 : // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
1737 2074 : node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
1738 2074 : NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
1739 1037 : } else if (CanBeTaggedPointer(input_info->representation())) {
1740 : // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
1741 1037 : node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
1742 1037 : NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
1743 : } else {
1744 : DCHECK(TypeOf(node->InputAt(0)).IsNone());
1745 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1746 : }
1747 : } else {
1748 : // No input representation requirement; adapt during lowering.
1749 6568 : ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
1750 : SetOutput(node, MachineRepresentation::kBit);
1751 : }
1752 : return;
1753 : }
1754 : case IrOpcode::kNumberEqual: {
1755 155695 : Type const lhs_type = TypeOf(node->InputAt(0));
1756 155695 : Type const rhs_type = TypeOf(node->InputAt(1));
1757 : // Regular number comparisons in JavaScript generally identify zeros,
1758 : // so we always pass kIdentifyZeros for the inputs, and in addition
1759 : // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
1760 : // For equality we also handle the case that one side is non-zero, in
1761 : // which case we allow to truncate NaN to 0 on the other side.
1762 209769 : if ((lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
1763 257382 : rhs_type.Is(Type::Unsigned32OrMinusZero())) ||
1764 102 : (lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1765 36 : rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1766 36 : OneInputCannotBe(node, type_cache_->kZeroish))) {
1767 : // => unsigned Int32Cmp
1768 : VisitBinop(node, UseInfo::TruncatingWord32(),
1769 : MachineRepresentation::kBit);
1770 66647 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1771 : return;
1772 : }
1773 122874 : if ((lhs_type.Is(Type::Signed32OrMinusZero()) &&
1774 182216 : rhs_type.Is(Type::Signed32OrMinusZero())) ||
1775 65 : (lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
1776 36 : rhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
1777 36 : OneInputCannotBe(node, type_cache_->kZeroish))) {
1778 : // => signed Int32Cmp
1779 : VisitBinop(node, UseInfo::TruncatingWord32(),
1780 : MachineRepresentation::kBit);
1781 27850 : if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1782 : return;
1783 : }
1784 : // => Float64Cmp
1785 : VisitBinop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
1786 : MachineRepresentation::kBit);
1787 89105 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1788 : return;
1789 : }
1790 : case IrOpcode::kNumberLessThan:
1791 : case IrOpcode::kNumberLessThanOrEqual: {
1792 164126 : Type const lhs_type = TypeOf(node->InputAt(0));
1793 164126 : Type const rhs_type = TypeOf(node->InputAt(1));
1794 : // Regular number comparisons in JavaScript generally identify zeros,
1795 : // so we always pass kIdentifyZeros for the inputs, and in addition
1796 : // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
1797 267374 : if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
1798 : rhs_type.Is(Type::Unsigned32OrMinusZero())) {
1799 : // => unsigned Int32Cmp
1800 : VisitBinop(node, UseInfo::TruncatingWord32(),
1801 : MachineRepresentation::kBit);
1802 115880 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1803 84665 : } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
1804 : rhs_type.Is(Type::Signed32OrMinusZero())) {
1805 : // => signed Int32Cmp
1806 : VisitBinop(node, UseInfo::TruncatingWord32(),
1807 : MachineRepresentation::kBit);
1808 13640 : if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1809 : } else {
1810 : // => Float64Cmp
1811 : VisitBinop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
1812 : MachineRepresentation::kBit);
1813 62519 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1814 : }
1815 : return;
1816 : }
1817 :
1818 : case IrOpcode::kSpeculativeSafeIntegerAdd:
1819 : case IrOpcode::kSpeculativeSafeIntegerSubtract:
1820 790020 : return VisitSpeculativeIntegerAdditiveOp(node, truncation, lowering);
1821 :
1822 : case IrOpcode::kSpeculativeNumberAdd:
1823 : case IrOpcode::kSpeculativeNumberSubtract:
1824 3887 : return VisitSpeculativeAdditiveOp(node, truncation, lowering);
1825 :
1826 : case IrOpcode::kSpeculativeNumberLessThan:
1827 : case IrOpcode::kSpeculativeNumberLessThanOrEqual:
1828 : case IrOpcode::kSpeculativeNumberEqual: {
1829 388954 : Type const lhs_type = TypeOf(node->InputAt(0));
1830 388954 : Type const rhs_type = TypeOf(node->InputAt(1));
1831 : // Regular number comparisons in JavaScript generally identify zeros,
1832 : // so we always pass kIdentifyZeros for the inputs, and in addition
1833 : // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
1834 658990 : if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
1835 : rhs_type.Is(Type::Unsigned32OrMinusZero())) {
1836 : // => unsigned Int32Cmp
1837 : VisitBinop(node, UseInfo::TruncatingWord32(),
1838 : MachineRepresentation::kBit);
1839 6209 : if (lower()) ChangeToPureOp(node, Uint32Op(node));
1840 : return;
1841 664266 : } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
1842 : rhs_type.Is(Type::Signed32OrMinusZero())) {
1843 : // => signed Int32Cmp
1844 : VisitBinop(node, UseInfo::TruncatingWord32(),
1845 : MachineRepresentation::kBit);
1846 246238 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1847 : return;
1848 : }
1849 : // Try to use type feedback.
1850 199936 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1851 199935 : switch (hint) {
1852 : case NumberOperationHint::kSigned32:
1853 : case NumberOperationHint::kSignedSmall:
1854 160634 : if (propagate()) {
1855 232872 : VisitBinop(node,
1856 : CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
1857 : kIdentifyZeros),
1858 : MachineRepresentation::kBit);
1859 44198 : } else if (retype()) {
1860 : SetOutput(node, MachineRepresentation::kBit, Type::Any());
1861 : } else {
1862 : DCHECK(lower());
1863 : Node* lhs = node->InputAt(0);
1864 : Node* rhs = node->InputAt(1);
1865 32068 : if (IsNodeRepresentationTagged(lhs) &&
1866 : IsNodeRepresentationTagged(rhs)) {
1867 28898 : VisitBinop(node,
1868 : UseInfo::CheckedSignedSmallAsTaggedSigned(
1869 : VectorSlotPair(), kIdentifyZeros),
1870 : MachineRepresentation::kBit);
1871 14449 : ChangeToPureOp(
1872 28898 : node, changer_->TaggedSignedOperatorFor(node->opcode()));
1873 :
1874 : } else {
1875 5348 : VisitBinop(node,
1876 : CheckedUseInfoAsWord32FromHint(
1877 : hint, VectorSlotPair(), kIdentifyZeros),
1878 : MachineRepresentation::kBit);
1879 2674 : ChangeToPureOp(node, Int32Op(node));
1880 : }
1881 : }
1882 : return;
1883 : case NumberOperationHint::kSignedSmallInputs:
1884 : // This doesn't make sense for compare operations.
1885 0 : UNREACHABLE();
1886 : case NumberOperationHint::kNumberOrOddball:
1887 : // Abstract and strict equality don't perform ToNumber conversions
1888 : // on Oddballs, so make sure we don't accidentially sneak in a
1889 : // hint with Oddball feedback here.
1890 : DCHECK_NE(IrOpcode::kSpeculativeNumberEqual, node->opcode());
1891 : V8_FALLTHROUGH;
1892 : case NumberOperationHint::kNumber:
1893 78602 : VisitBinop(node,
1894 : CheckedUseInfoAsFloat64FromHint(hint, VectorSlotPair(),
1895 : kIdentifyZeros),
1896 : MachineRepresentation::kBit);
1897 48606 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1898 : return;
1899 : }
1900 0 : UNREACHABLE();
1901 : return;
1902 : }
1903 :
1904 : case IrOpcode::kNumberAdd:
1905 : case IrOpcode::kNumberSubtract: {
1906 1537779 : if (TypeOf(node->InputAt(0))
1907 1300224 : .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1908 1300212 : TypeOf(node->InputAt(1))
1909 1206795 : .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1910 1488440 : (TypeOf(node).Is(Type::Signed32()) ||
1911 548722 : TypeOf(node).Is(Type::Unsigned32()) ||
1912 : truncation.IsUsedAsWord32())) {
1913 : // => Int32Add/Sub
1914 171672 : VisitWord32TruncatingBinop(node);
1915 210187 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1916 2387154 : } else if (jsgraph_->machine()->Is64() &&
1917 598921 : BothInputsAre(node, type_cache_->kSafeInteger) &&
1918 600627 : GetUpperBound(node).Is(type_cache_->kSafeInteger)) {
1919 : // => Int64Add/Sub
1920 1678 : VisitInt64Binop(node);
1921 2203 : if (lower()) ChangeToPureOp(node, Int64Op(node));
1922 : } else {
1923 : // => Float64Add/Sub
1924 595537 : VisitFloat64Binop(node);
1925 668737 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1926 : }
1927 : return;
1928 : }
1929 : case IrOpcode::kSpeculativeNumberMultiply: {
1930 128118 : if (BothInputsAre(node, Type::Integral32()) &&
1931 57160 : (NodeProperties::GetType(node).Is(Type::Signed32()) ||
1932 50096 : NodeProperties::GetType(node).Is(Type::Unsigned32()) ||
1933 420 : (truncation.IsUsedAsWord32() &&
1934 43126 : NodeProperties::GetType(node).Is(
1935 420 : type_cache_->kSafeIntegerOrMinusZero)))) {
1936 : // Multiply reduces to Int32Mul if the inputs are integers, and
1937 : // (a) the output is either known to be Signed32, or
1938 : // (b) the output is known to be Unsigned32, or
1939 : // (c) the uses are truncating and the result is in the safe
1940 : // integer range.
1941 2081 : VisitWord32TruncatingBinop(node);
1942 2636 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1943 : return;
1944 : }
1945 : // Try to use type feedback.
1946 40625 : NumberOperationHint hint = NumberOperationHintOf(node->op());
1947 40625 : Type input0_type = TypeOf(node->InputAt(0));
1948 40625 : Type input1_type = TypeOf(node->InputAt(1));
1949 :
1950 : // Handle the case when no int32 checks on inputs are necessary
1951 : // (but an overflow check is needed on the output).
1952 40625 : if (BothInputsAre(node, Type::Signed32())) {
1953 : // If both inputs and feedback are int32, use the overflow op.
1954 5706 : if (hint == NumberOperationHint::kSignedSmall ||
1955 2853 : hint == NumberOperationHint::kSigned32) {
1956 : VisitBinop(node, UseInfo::TruncatingWord32(),
1957 : MachineRepresentation::kWord32, Type::Signed32());
1958 2853 : if (lower()) {
1959 : LowerToCheckedInt32Mul(node, truncation, input0_type,
1960 915 : input1_type);
1961 : }
1962 : return;
1963 : }
1964 : }
1965 :
1966 75544 : if (hint == NumberOperationHint::kSignedSmall ||
1967 37772 : hint == NumberOperationHint::kSigned32) {
1968 36086 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1969 : MachineRepresentation::kWord32, Type::Signed32());
1970 18043 : if (lower()) {
1971 5331 : LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type);
1972 : }
1973 : return;
1974 : }
1975 :
1976 : // Checked float64 x float64 => float64
1977 39458 : VisitBinop(node,
1978 : UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1979 : VectorSlotPair()),
1980 : MachineRepresentation::kFloat64, Type::Number());
1981 25311 : if (lower()) ChangeToPureOp(node, Float64Op(node));
1982 : return;
1983 : }
1984 : case IrOpcode::kNumberMultiply: {
1985 55103 : if (TypeOf(node->InputAt(0)).Is(Type::Integral32()) &&
1986 59810 : TypeOf(node->InputAt(1)).Is(Type::Integral32()) &&
1987 31792 : (TypeOf(node).Is(Type::Signed32()) ||
1988 30084 : TypeOf(node).Is(Type::Unsigned32()) ||
1989 575 : (truncation.IsUsedAsWord32() &&
1990 25215 : TypeOf(node).Is(type_cache_->kSafeIntegerOrMinusZero)))) {
1991 : // Multiply reduces to Int32Mul if the inputs are integers, and
1992 : // (a) the output is either known to be Signed32, or
1993 : // (b) the output is known to be Unsigned32, or
1994 : // (c) the uses are truncating and the result is in the safe
1995 : // integer range.
1996 2259 : VisitWord32TruncatingBinop(node);
1997 2724 : if (lower()) ChangeToPureOp(node, Int32Op(node));
1998 : return;
1999 : }
2000 : // Number x Number => Float64Mul
2001 21806 : VisitFloat64Binop(node);
2002 27849 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2003 : return;
2004 : }
2005 : case IrOpcode::kSpeculativeNumberDivide: {
2006 58643 : if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
2007 : // => unsigned Uint32Div
2008 577 : VisitWord32TruncatingBinop(node);
2009 577 : if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
2010 : return;
2011 : }
2012 51320 : if (BothInputsAreSigned32(node)) {
2013 30548 : if (NodeProperties::GetType(node).Is(Type::Signed32())) {
2014 : // => signed Int32Div
2015 0 : VisitWord32TruncatingBinop(node);
2016 0 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2017 : return;
2018 : }
2019 15274 : if (truncation.IsUsedAsWord32()) {
2020 : // => signed Int32Div
2021 6937 : VisitWord32TruncatingBinop(node);
2022 6937 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2023 : return;
2024 : }
2025 : }
2026 :
2027 : // Try to use type feedback.
2028 44383 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2029 :
2030 : // Handle the case when no uint32 checks on inputs are necessary
2031 : // (but an overflow check is needed on the output).
2032 44383 : if (BothInputsAreUnsigned32(node)) {
2033 12338 : if (hint == NumberOperationHint::kSignedSmall ||
2034 6169 : hint == NumberOperationHint::kSigned32) {
2035 : VisitBinop(node, UseInfo::TruncatingWord32(),
2036 : MachineRepresentation::kWord32, Type::Unsigned32());
2037 289 : if (lower()) ChangeToUint32OverflowOp(node);
2038 : return;
2039 : }
2040 : }
2041 :
2042 : // Handle the case when no int32 checks on inputs are necessary
2043 : // (but an overflow check is needed on the output).
2044 44094 : if (BothInputsAreSigned32(node)) {
2045 : // If both the inputs the feedback are int32, use the overflow op.
2046 16120 : if (hint == NumberOperationHint::kSignedSmall ||
2047 8060 : hint == NumberOperationHint::kSigned32) {
2048 : VisitBinop(node, UseInfo::TruncatingWord32(),
2049 : MachineRepresentation::kWord32, Type::Signed32());
2050 12 : if (lower()) ChangeToInt32OverflowOp(node);
2051 : return;
2052 : }
2053 : }
2054 :
2055 88164 : if (hint == NumberOperationHint::kSigned32 ||
2056 87268 : hint == NumberOperationHint::kSignedSmall ||
2057 : hint == NumberOperationHint::kSignedSmallInputs) {
2058 : // If the result is truncated, we only need to check the inputs.
2059 37767 : if (truncation.IsUsedAsWord32()) {
2060 4854 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2061 : MachineRepresentation::kWord32);
2062 2427 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2063 : return;
2064 35340 : } else if (hint != NumberOperationHint::kSignedSmallInputs) {
2065 1598 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2066 : MachineRepresentation::kWord32, Type::Signed32());
2067 799 : if (lower()) ChangeToInt32OverflowOp(node);
2068 : return;
2069 : }
2070 : }
2071 :
2072 : // default case => Float64Div
2073 81712 : VisitBinop(node,
2074 : UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
2075 : VectorSlotPair()),
2076 : MachineRepresentation::kFloat64, Type::Number());
2077 52759 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2078 : return;
2079 : }
2080 : case IrOpcode::kNumberDivide: {
2081 36532 : if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
2082 37339 : TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
2083 665 : (truncation.IsUsedAsWord32() ||
2084 14319 : TypeOf(node).Is(Type::Unsigned32()))) {
2085 : // => unsigned Uint32Div
2086 142 : VisitWord32TruncatingBinop(node);
2087 142 : if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
2088 : return;
2089 : }
2090 36192 : if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
2091 37638 : TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
2092 1438 : (truncation.IsUsedAsWord32() ||
2093 14950 : TypeOf(node).Is(Type::Signed32()))) {
2094 : // => signed Int32Div
2095 8 : VisitWord32TruncatingBinop(node);
2096 8 : if (lower()) DeferReplacement(node, lowering->Int32Div(node));
2097 : return;
2098 : }
2099 : // Number x Number => Float64Div
2100 13504 : VisitFloat64Binop(node);
2101 16871 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2102 : return;
2103 : }
2104 : case IrOpcode::kSpeculativeNumberModulus:
2105 13904 : return VisitSpeculativeNumberModulus(node, truncation, lowering);
2106 : case IrOpcode::kNumberModulus: {
2107 2564 : Type const lhs_type = TypeOf(node->InputAt(0));
2108 2564 : Type const rhs_type = TypeOf(node->InputAt(1));
2109 5426 : if ((lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2110 2884 : rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) &&
2111 153 : (truncation.IsUsedAsWord32() ||
2112 2870 : TypeOf(node).Is(Type::Unsigned32()))) {
2113 : // => unsigned Uint32Mod
2114 320 : VisitWord32TruncatingBinop(node);
2115 320 : if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
2116 : return;
2117 : }
2118 4761 : if ((lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2119 2452 : rhs_type.Is(Type::Signed32OrMinusZeroOrNaN())) &&
2120 2754 : (truncation.IsUsedAsWord32() || TypeOf(node).Is(Type::Signed32()) ||
2121 42 : (truncation.IdentifiesZeroAndMinusZero() &&
2122 2286 : TypeOf(node).Is(Type::Signed32OrMinusZero())))) {
2123 : // => signed Int32Mod
2124 98 : VisitWord32TruncatingBinop(node);
2125 98 : if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
2126 : return;
2127 : }
2128 : // => Float64Mod
2129 : // For the left hand side we just propagate the identify zeros
2130 : // mode of the {truncation}; and for modulus the sign of the
2131 : // right hand side doesn't matter anyways, so in particular there's
2132 : // no observable difference between a 0 and a -0 then.
2133 : UseInfo const lhs_use =
2134 : UseInfo::TruncatingFloat64(truncation.identify_zeros());
2135 : UseInfo const rhs_use = UseInfo::TruncatingFloat64(kIdentifyZeros);
2136 2146 : VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64);
2137 2500 : if (lower()) ChangeToPureOp(node, Float64Op(node));
2138 : return;
2139 : }
2140 : case IrOpcode::kNumberBitwiseOr:
2141 : case IrOpcode::kNumberBitwiseXor:
2142 : case IrOpcode::kNumberBitwiseAnd: {
2143 19729 : VisitWord32TruncatingBinop(node);
2144 26190 : if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
2145 : return;
2146 : }
2147 : case IrOpcode::kSpeculativeNumberBitwiseOr:
2148 : case IrOpcode::kSpeculativeNumberBitwiseXor:
2149 : case IrOpcode::kSpeculativeNumberBitwiseAnd:
2150 81805 : VisitSpeculativeInt32Binop(node);
2151 81804 : if (lower()) {
2152 22508 : ChangeToPureOp(node, Int32Op(node));
2153 : }
2154 : return;
2155 : case IrOpcode::kNumberShiftLeft: {
2156 1293 : Type rhs_type = GetUpperBound(node->InputAt(1));
2157 : VisitBinop(node, UseInfo::TruncatingWord32(),
2158 1293 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2159 1293 : if (lower()) {
2160 376 : MaskShiftOperand(node, rhs_type);
2161 376 : ChangeToPureOp(node, lowering->machine()->Word32Shl());
2162 : }
2163 : return;
2164 : }
2165 : case IrOpcode::kSpeculativeNumberShiftLeft: {
2166 8098 : if (BothInputsAre(node, Type::NumberOrOddball())) {
2167 7297 : Type rhs_type = GetUpperBound(node->InputAt(1));
2168 : VisitBinop(node, UseInfo::TruncatingWord32(),
2169 : UseInfo::TruncatingWord32(),
2170 7297 : MachineRepresentation::kWord32);
2171 7297 : if (lower()) {
2172 1845 : MaskShiftOperand(node, rhs_type);
2173 1845 : ChangeToPureOp(node, lowering->machine()->Word32Shl());
2174 : }
2175 : return;
2176 : }
2177 801 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2178 801 : Type rhs_type = GetUpperBound(node->InputAt(1));
2179 1602 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2180 : MachineRepresentation::kWord32, Type::Signed32());
2181 801 : if (lower()) {
2182 258 : MaskShiftOperand(node, rhs_type);
2183 258 : ChangeToPureOp(node, lowering->machine()->Word32Shl());
2184 : }
2185 : return;
2186 : }
2187 : case IrOpcode::kNumberShiftRight: {
2188 555 : Type rhs_type = GetUpperBound(node->InputAt(1));
2189 : VisitBinop(node, UseInfo::TruncatingWord32(),
2190 555 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2191 555 : if (lower()) {
2192 155 : MaskShiftOperand(node, rhs_type);
2193 155 : ChangeToPureOp(node, lowering->machine()->Word32Sar());
2194 : }
2195 : return;
2196 : }
2197 : case IrOpcode::kSpeculativeNumberShiftRight: {
2198 22814 : if (BothInputsAre(node, Type::NumberOrOddball())) {
2199 21581 : Type rhs_type = GetUpperBound(node->InputAt(1));
2200 : VisitBinop(node, UseInfo::TruncatingWord32(),
2201 : UseInfo::TruncatingWord32(),
2202 21581 : MachineRepresentation::kWord32);
2203 21581 : if (lower()) {
2204 5213 : MaskShiftOperand(node, rhs_type);
2205 5213 : ChangeToPureOp(node, lowering->machine()->Word32Sar());
2206 : }
2207 : return;
2208 : }
2209 1233 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2210 1233 : Type rhs_type = GetUpperBound(node->InputAt(1));
2211 2466 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2212 : MachineRepresentation::kWord32, Type::Signed32());
2213 1233 : if (lower()) {
2214 380 : MaskShiftOperand(node, rhs_type);
2215 380 : ChangeToPureOp(node, lowering->machine()->Word32Sar());
2216 : }
2217 : return;
2218 : }
2219 : case IrOpcode::kNumberShiftRightLogical: {
2220 683 : Type rhs_type = GetUpperBound(node->InputAt(1));
2221 : VisitBinop(node, UseInfo::TruncatingWord32(),
2222 683 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2223 683 : if (lower()) {
2224 209 : MaskShiftOperand(node, rhs_type);
2225 209 : ChangeToPureOp(node, lowering->machine()->Word32Shr());
2226 : }
2227 : return;
2228 : }
2229 : case IrOpcode::kSpeculativeNumberShiftRightLogical: {
2230 5936 : NumberOperationHint hint = NumberOperationHintOf(node->op());
2231 5936 : Type rhs_type = GetUpperBound(node->InputAt(1));
2232 15113 : if (rhs_type.Is(type_cache_->kZeroish) &&
2233 6480 : (hint == NumberOperationHint::kSignedSmall ||
2234 9840 : hint == NumberOperationHint::kSigned32) &&
2235 : !truncation.IsUsedAsWord32()) {
2236 : // The SignedSmall or Signed32 feedback means that the results that we
2237 : // have seen so far were of type Unsigned31. We speculate that this
2238 : // will continue to hold. Moreover, since the RHS is 0, the result
2239 : // will just be the (converted) LHS.
2240 650 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2241 : MachineRepresentation::kWord32, Type::Unsigned31());
2242 325 : if (lower()) {
2243 92 : node->RemoveInput(1);
2244 184 : NodeProperties::ChangeOp(
2245 92 : node, simplified()->CheckedUint32ToInt32(VectorSlotPair()));
2246 : }
2247 : return;
2248 : }
2249 5612 : if (BothInputsAre(node, Type::NumberOrOddball())) {
2250 : VisitBinop(node, UseInfo::TruncatingWord32(),
2251 : UseInfo::TruncatingWord32(),
2252 4221 : MachineRepresentation::kWord32);
2253 4221 : if (lower()) {
2254 1194 : MaskShiftOperand(node, rhs_type);
2255 1194 : ChangeToPureOp(node, lowering->machine()->Word32Shr());
2256 : }
2257 : return;
2258 : }
2259 2782 : VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
2260 : MachineRepresentation::kWord32, Type::Unsigned32());
2261 1391 : if (lower()) {
2262 423 : MaskShiftOperand(node, rhs_type);
2263 423 : ChangeToPureOp(node, lowering->machine()->Word32Shr());
2264 : }
2265 : return;
2266 : }
2267 : case IrOpcode::kNumberAbs: {
2268 : // NumberAbs maps both 0 and -0 to 0, so we can generally
2269 : // pass the kIdentifyZeros truncation to its input, and
2270 : // choose to ignore minus zero in all cases.
2271 903 : Type const input_type = TypeOf(node->InputAt(0));
2272 903 : if (input_type.Is(Type::Unsigned32OrMinusZero())) {
2273 : VisitUnop(node, UseInfo::TruncatingWord32(),
2274 37 : MachineRepresentation::kWord32);
2275 52 : if (lower()) DeferReplacement(node, node->InputAt(0));
2276 866 : } else if (input_type.Is(Type::Signed32OrMinusZero())) {
2277 : VisitUnop(node, UseInfo::TruncatingWord32(),
2278 208 : MachineRepresentation::kWord32);
2279 208 : if (lower()) DeferReplacement(node, lowering->Int32Abs(node));
2280 1316 : } else if (input_type.Is(type_cache_->kPositiveIntegerOrNaN)) {
2281 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2282 14 : MachineRepresentation::kFloat64);
2283 21 : if (lower()) DeferReplacement(node, node->InputAt(0));
2284 : } else {
2285 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2286 644 : MachineRepresentation::kFloat64);
2287 834 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2288 : }
2289 : return;
2290 : }
2291 : case IrOpcode::kNumberClz32: {
2292 : VisitUnop(node, UseInfo::TruncatingWord32(),
2293 84 : MachineRepresentation::kWord32);
2294 112 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
2295 : return;
2296 : }
2297 : case IrOpcode::kNumberImul: {
2298 : VisitBinop(node, UseInfo::TruncatingWord32(),
2299 2616 : UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
2300 3488 : if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
2301 : return;
2302 : }
2303 : case IrOpcode::kNumberFround: {
2304 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2305 3900 : MachineRepresentation::kFloat32);
2306 5187 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2307 : return;
2308 : }
2309 : case IrOpcode::kNumberMax: {
2310 : // It is safe to use the feedback types for left and right hand side
2311 : // here, since we can only narrow those types and thus we can only
2312 : // promise a more specific truncation.
2313 : // For NumberMax we generally propagate whether the truncation
2314 : // identifies zeros to the inputs, and we choose to ignore minus
2315 : // zero in those cases.
2316 7554 : Type const lhs_type = TypeOf(node->InputAt(0));
2317 7554 : Type const rhs_type = TypeOf(node->InputAt(1));
2318 11625 : if ((lhs_type.Is(Type::Unsigned32()) &&
2319 11646 : rhs_type.Is(Type::Unsigned32())) ||
2320 681 : (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2321 102 : rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2322 : truncation.IdentifiesZeroAndMinusZero())) {
2323 3483 : VisitWord32TruncatingBinop(node);
2324 3483 : if (lower()) {
2325 1107 : lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
2326 1107 : MachineRepresentation::kWord32);
2327 : }
2328 7831 : } else if ((lhs_type.Is(Type::Signed32()) &&
2329 4956 : rhs_type.Is(Type::Signed32())) ||
2330 625 : (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2331 81 : rhs_type.Is(Type::Signed32OrMinusZero()) &&
2332 : truncation.IdentifiesZeroAndMinusZero())) {
2333 3186 : VisitWord32TruncatingBinop(node);
2334 3186 : if (lower()) {
2335 1041 : lowering->DoMax(node, lowering->machine()->Int32LessThan(),
2336 1041 : MachineRepresentation::kWord32);
2337 : }
2338 2655 : } else if (jsgraph_->machine()->Is64() &&
2339 1512 : lhs_type.Is(type_cache_->kSafeInteger) &&
2340 627 : rhs_type.Is(type_cache_->kSafeInteger)) {
2341 501 : VisitInt64Binop(node);
2342 501 : if (lower()) {
2343 164 : lowering->DoMax(node, lowering->machine()->Int64LessThan(),
2344 164 : MachineRepresentation::kWord64);
2345 : }
2346 : } else {
2347 : VisitBinop(node,
2348 : UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2349 : MachineRepresentation::kFloat64);
2350 384 : if (lower()) {
2351 : // If the right hand side is not NaN, and the left hand side
2352 : // is not NaN (or -0 if the difference between the zeros is
2353 : // observed), we can do a simple floating point comparison here.
2354 240 : if (lhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2355 : ? Type::OrderedNumber()
2356 193 : : Type::PlainNumber()) &&
2357 : rhs_type.Is(Type::OrderedNumber())) {
2358 48 : lowering->DoMax(node, lowering->machine()->Float64LessThan(),
2359 48 : MachineRepresentation::kFloat64);
2360 : } else {
2361 72 : NodeProperties::ChangeOp(node, Float64Op(node));
2362 : }
2363 : }
2364 : }
2365 : return;
2366 : }
2367 : case IrOpcode::kNumberMin: {
2368 : // It is safe to use the feedback types for left and right hand side
2369 : // here, since we can only narrow those types and thus we can only
2370 : // promise a more specific truncation.
2371 : // For NumberMin we generally propagate whether the truncation
2372 : // identifies zeros to the inputs, and we choose to ignore minus
2373 : // zero in those cases.
2374 10241 : Type const lhs_type = TypeOf(node->InputAt(0));
2375 10241 : Type const rhs_type = TypeOf(node->InputAt(1));
2376 19864 : if ((lhs_type.Is(Type::Unsigned32()) &&
2377 11104 : rhs_type.Is(Type::Unsigned32())) ||
2378 299 : (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2379 81 : rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2380 : truncation.IdentifiesZeroAndMinusZero())) {
2381 9378 : VisitWord32TruncatingBinop(node);
2382 9378 : if (lower()) {
2383 3008 : lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
2384 3008 : MachineRepresentation::kWord32);
2385 : }
2386 1254 : } else if ((lhs_type.Is(Type::Signed32()) &&
2387 1498 : rhs_type.Is(Type::Signed32())) ||
2388 217 : (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2389 81 : rhs_type.Is(Type::Signed32OrMinusZero()) &&
2390 : truncation.IdentifiesZeroAndMinusZero())) {
2391 228 : VisitWord32TruncatingBinop(node);
2392 228 : if (lower()) {
2393 70 : lowering->DoMin(node, lowering->machine()->Int32LessThan(),
2394 70 : MachineRepresentation::kWord32);
2395 : }
2396 1905 : } else if (jsgraph_->machine()->Is64() &&
2397 822 : lhs_type.Is(type_cache_->kSafeInteger) &&
2398 187 : rhs_type.Is(type_cache_->kSafeInteger)) {
2399 40 : VisitInt64Binop(node);
2400 40 : if (lower()) {
2401 16 : lowering->DoMin(node, lowering->machine()->Int64LessThan(),
2402 16 : MachineRepresentation::kWord64);
2403 : }
2404 : } else {
2405 : VisitBinop(node,
2406 : UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2407 : MachineRepresentation::kFloat64);
2408 595 : if (lower()) {
2409 : // If the left hand side is not NaN, and the right hand side
2410 : // is not NaN (or -0 if the difference between the zeros is
2411 : // observed), we can do a simple floating point comparison here.
2412 277 : if (lhs_type.Is(Type::OrderedNumber()) &&
2413 84 : rhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2414 : ? Type::OrderedNumber()
2415 : : Type::PlainNumber())) {
2416 45 : lowering->DoMin(node,
2417 : lowering->machine()->Float64LessThanOrEqual(),
2418 45 : MachineRepresentation::kFloat64);
2419 : } else {
2420 148 : NodeProperties::ChangeOp(node, Float64Op(node));
2421 : }
2422 : }
2423 : }
2424 : return;
2425 : }
2426 : case IrOpcode::kNumberAtan2:
2427 : case IrOpcode::kNumberPow: {
2428 : VisitBinop(node, UseInfo::TruncatingFloat64(),
2429 : MachineRepresentation::kFloat64);
2430 3708 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2431 : return;
2432 : }
2433 : case IrOpcode::kNumberCeil:
2434 : case IrOpcode::kNumberFloor:
2435 : case IrOpcode::kNumberRound:
2436 : case IrOpcode::kNumberTrunc: {
2437 : // For NumberCeil, NumberFloor, NumberRound and NumberTrunc we propagate
2438 : // the zero identification part of the truncation, and we turn them into
2439 : // no-ops if we figure out (late) that their input is already an
2440 : // integer, NaN or -0.
2441 134540 : Type const input_type = TypeOf(node->InputAt(0));
2442 : VisitUnop(node, UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2443 134540 : MachineRepresentation::kFloat64);
2444 134540 : if (lower()) {
2445 88524 : if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2446 1246 : DeferReplacement(node, node->InputAt(0));
2447 43016 : } else if (node->opcode() == IrOpcode::kNumberRound) {
2448 1554 : DeferReplacement(node, lowering->Float64Round(node));
2449 : } else {
2450 41462 : NodeProperties::ChangeOp(node, Float64Op(node));
2451 : }
2452 : }
2453 : return;
2454 : }
2455 : case IrOpcode::kNumberAcos:
2456 : case IrOpcode::kNumberAcosh:
2457 : case IrOpcode::kNumberAsin:
2458 : case IrOpcode::kNumberAsinh:
2459 : case IrOpcode::kNumberAtan:
2460 : case IrOpcode::kNumberAtanh:
2461 : case IrOpcode::kNumberCos:
2462 : case IrOpcode::kNumberCosh:
2463 : case IrOpcode::kNumberExp:
2464 : case IrOpcode::kNumberExpm1:
2465 : case IrOpcode::kNumberLog:
2466 : case IrOpcode::kNumberLog1p:
2467 : case IrOpcode::kNumberLog2:
2468 : case IrOpcode::kNumberLog10:
2469 : case IrOpcode::kNumberCbrt:
2470 : case IrOpcode::kNumberSin:
2471 : case IrOpcode::kNumberSinh:
2472 : case IrOpcode::kNumberTan:
2473 : case IrOpcode::kNumberTanh: {
2474 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2475 858 : MachineRepresentation::kFloat64);
2476 1136 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2477 : return;
2478 : }
2479 : case IrOpcode::kNumberSign: {
2480 111 : if (InputIs(node, Type::Signed32())) {
2481 : VisitUnop(node, UseInfo::TruncatingWord32(),
2482 21 : MachineRepresentation::kWord32);
2483 21 : if (lower()) DeferReplacement(node, lowering->Int32Sign(node));
2484 : } else {
2485 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2486 90 : MachineRepresentation::kFloat64);
2487 90 : if (lower()) DeferReplacement(node, lowering->Float64Sign(node));
2488 : }
2489 : return;
2490 : }
2491 : case IrOpcode::kNumberSilenceNaN: {
2492 2276 : Type const input_type = TypeOf(node->InputAt(0));
2493 2276 : if (input_type.Is(Type::OrderedNumber())) {
2494 : // No need to silence anything if the input cannot be NaN.
2495 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2496 14 : MachineRepresentation::kFloat64);
2497 21 : if (lower()) DeferReplacement(node, node->InputAt(0));
2498 : } else {
2499 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2500 2262 : MachineRepresentation::kFloat64);
2501 2994 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2502 : }
2503 : return;
2504 : }
2505 : case IrOpcode::kNumberSqrt: {
2506 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2507 156 : MachineRepresentation::kFloat64);
2508 207 : if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2509 : return;
2510 : }
2511 : case IrOpcode::kNumberToBoolean: {
2512 : // For NumberToBoolean we don't care whether the input is 0 or
2513 : // -0, since both of them are mapped to false anyways, so we
2514 : // can generally pass kIdentifyZeros truncation.
2515 558 : Type const input_type = TypeOf(node->InputAt(0));
2516 558 : if (input_type.Is(Type::Integral32OrMinusZeroOrNaN())) {
2517 : // 0, -0 and NaN all map to false, so we can safely truncate
2518 : // all of them to zero here.
2519 : VisitUnop(node, UseInfo::TruncatingWord32(),
2520 305 : MachineRepresentation::kBit);
2521 305 : if (lower()) lowering->DoIntegral32ToBit(node);
2522 253 : } else if (input_type.Is(Type::OrderedNumber())) {
2523 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2524 77 : MachineRepresentation::kBit);
2525 77 : if (lower()) lowering->DoOrderedNumberToBit(node);
2526 : } else {
2527 : VisitUnop(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2528 176 : MachineRepresentation::kBit);
2529 176 : if (lower()) lowering->DoNumberToBit(node);
2530 : }
2531 : return;
2532 : }
2533 : case IrOpcode::kNumberToInt32: {
2534 : // Just change representation if necessary.
2535 : VisitUnop(node, UseInfo::TruncatingWord32(),
2536 1621 : MachineRepresentation::kWord32);
2537 1906 : if (lower()) DeferReplacement(node, node->InputAt(0));
2538 : return;
2539 : }
2540 : case IrOpcode::kNumberToString: {
2541 : VisitUnop(node, UseInfo::AnyTagged(),
2542 11187 : MachineRepresentation::kTaggedPointer);
2543 11187 : return;
2544 : }
2545 : case IrOpcode::kNumberToUint32: {
2546 : // Just change representation if necessary.
2547 : VisitUnop(node, UseInfo::TruncatingWord32(),
2548 6270 : MachineRepresentation::kWord32);
2549 8232 : if (lower()) DeferReplacement(node, node->InputAt(0));
2550 : return;
2551 : }
2552 : case IrOpcode::kNumberToUint8Clamped: {
2553 1446 : Type const input_type = TypeOf(node->InputAt(0));
2554 2892 : if (input_type.Is(type_cache_->kUint8OrMinusZeroOrNaN)) {
2555 : VisitUnop(node, UseInfo::TruncatingWord32(),
2556 45 : MachineRepresentation::kWord32);
2557 60 : if (lower()) DeferReplacement(node, node->InputAt(0));
2558 1401 : } else if (input_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) {
2559 : VisitUnop(node, UseInfo::TruncatingWord32(),
2560 240 : MachineRepresentation::kWord32);
2561 240 : if (lower()) lowering->DoUnsigned32ToUint8Clamped(node);
2562 1161 : } else if (input_type.Is(Type::Signed32OrMinusZeroOrNaN())) {
2563 : VisitUnop(node, UseInfo::TruncatingWord32(),
2564 216 : MachineRepresentation::kWord32);
2565 216 : if (lower()) lowering->DoSigned32ToUint8Clamped(node);
2566 1890 : } else if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2567 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2568 63 : MachineRepresentation::kFloat64);
2569 63 : if (lower()) lowering->DoIntegerToUint8Clamped(node);
2570 : } else {
2571 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2572 882 : MachineRepresentation::kFloat64);
2573 882 : if (lower()) lowering->DoNumberToUint8Clamped(node);
2574 : }
2575 : return;
2576 : }
2577 : case IrOpcode::kReferenceEqual: {
2578 : VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2579 601816 : if (lower()) {
2580 198716 : NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
2581 : }
2582 : return;
2583 : }
2584 : case IrOpcode::kSameValue: {
2585 234 : if (truncation.IsUnused()) return VisitUnused(node);
2586 234 : if (BothInputsAre(node, Type::Number())) {
2587 : VisitBinop(node, UseInfo::TruncatingFloat64(),
2588 : MachineRepresentation::kBit);
2589 231 : if (lower()) {
2590 77 : NodeProperties::ChangeOp(node,
2591 77 : lowering->simplified()->NumberSameValue());
2592 : }
2593 : } else {
2594 : VisitBinop(node, UseInfo::AnyTagged(),
2595 : MachineRepresentation::kTaggedPointer);
2596 : }
2597 : return;
2598 : }
2599 : case IrOpcode::kTypeOf: {
2600 : return VisitUnop(node, UseInfo::AnyTagged(),
2601 66540 : MachineRepresentation::kTaggedPointer);
2602 : }
2603 : case IrOpcode::kStringConcat: {
2604 82893 : Type const length_type = TypeOf(node->InputAt(0));
2605 82893 : Type const first_type = TypeOf(node->InputAt(1));
2606 82893 : Type const second_type = TypeOf(node->InputAt(2));
2607 186153 : if (length_type.Is(type_cache_->kConsStringLengthType) &&
2608 99026 : first_type.Is(Type::NonEmptyString()) &&
2609 : second_type.Is(Type::NonEmptyString())) {
2610 : // We know that we'll construct a ConsString here, so we
2611 : // can inline a fast-path into TurboFan optimized code.
2612 12624 : ProcessInput(node, 0, UseInfo::TruncatingWord32()); // length
2613 12624 : ProcessInput(node, 1, UseInfo::AnyTagged()); // first
2614 12624 : ProcessInput(node, 2, UseInfo::AnyTagged()); // second
2615 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2616 12624 : if (lower()) {
2617 9052 : if (first_type.Is(Type::NonEmptyOneByteString()) &&
2618 : second_type.Is(Type::NonEmptyOneByteString())) {
2619 3965 : NodeProperties::ChangeOp(
2620 3965 : node, lowering->simplified()->NewConsOneByteString());
2621 2196 : } else if (first_type.Is(Type::NonEmptyTwoByteString()) ||
2622 : second_type.Is(Type::NonEmptyTwoByteString())) {
2623 33 : NodeProperties::ChangeOp(
2624 33 : node, lowering->simplified()->NewConsTwoByteString());
2625 : } else {
2626 1081 : NodeProperties::ChangeOp(node,
2627 1081 : lowering->simplified()->NewConsString());
2628 : }
2629 : }
2630 : } else {
2631 70269 : ProcessInput(node, 0, UseInfo::TaggedSigned()); // length
2632 70269 : ProcessInput(node, 1, UseInfo::AnyTagged()); // first
2633 70269 : ProcessInput(node, 2, UseInfo::AnyTagged()); // second
2634 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2635 : }
2636 : return;
2637 : }
2638 : case IrOpcode::kStringEqual:
2639 : case IrOpcode::kStringLessThan:
2640 : case IrOpcode::kStringLessThanOrEqual: {
2641 : return VisitBinop(node, UseInfo::AnyTagged(),
2642 : MachineRepresentation::kTaggedPointer);
2643 : }
2644 : case IrOpcode::kStringCharCodeAt: {
2645 : return VisitBinop(node, UseInfo::AnyTagged(), UseInfo::Word(),
2646 8198 : MachineRepresentation::kWord32);
2647 : }
2648 : case IrOpcode::kStringCodePointAt: {
2649 : return VisitBinop(node, UseInfo::AnyTagged(), UseInfo::Word(),
2650 721 : MachineRepresentation::kTaggedSigned);
2651 : }
2652 : case IrOpcode::kStringFromSingleCharCode: {
2653 : VisitUnop(node, UseInfo::TruncatingWord32(),
2654 3564 : MachineRepresentation::kTaggedPointer);
2655 3564 : return;
2656 : }
2657 : case IrOpcode::kStringFromSingleCodePoint: {
2658 : VisitUnop(node, UseInfo::TruncatingWord32(),
2659 718 : MachineRepresentation::kTaggedPointer);
2660 718 : return;
2661 : }
2662 : case IrOpcode::kStringIndexOf: {
2663 816 : ProcessInput(node, 0, UseInfo::AnyTagged());
2664 816 : ProcessInput(node, 1, UseInfo::AnyTagged());
2665 816 : ProcessInput(node, 2, UseInfo::TaggedSigned());
2666 : SetOutput(node, MachineRepresentation::kTaggedSigned);
2667 : return;
2668 : }
2669 : case IrOpcode::kStringLength: {
2670 : // TODO(bmeurer): The input representation should be TaggedPointer.
2671 : // Fix this once we have a dedicated StringConcat/JSStringAdd
2672 : // operator, which marks it's output as TaggedPointer properly.
2673 72936 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kWord32);
2674 72936 : return;
2675 : }
2676 : case IrOpcode::kStringSubstring: {
2677 4039 : ProcessInput(node, 0, UseInfo::AnyTagged());
2678 4039 : ProcessInput(node, 1, UseInfo::TruncatingWord32());
2679 4039 : ProcessInput(node, 2, UseInfo::TruncatingWord32());
2680 4039 : ProcessRemainingInputs(node, 3);
2681 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2682 : return;
2683 : }
2684 : case IrOpcode::kStringToLowerCaseIntl:
2685 : case IrOpcode::kStringToUpperCaseIntl: {
2686 : VisitUnop(node, UseInfo::AnyTagged(),
2687 461 : MachineRepresentation::kTaggedPointer);
2688 461 : return;
2689 : }
2690 : case IrOpcode::kCheckBounds:
2691 187568 : return VisitCheckBounds(node, lowering);
2692 : case IrOpcode::kPoisonIndex: {
2693 : VisitUnop(node, UseInfo::TruncatingWord32(),
2694 3803 : MachineRepresentation::kWord32);
2695 3803 : return;
2696 : }
2697 : case IrOpcode::kCheckHeapObject: {
2698 89652 : if (InputCannotBe(node, Type::SignedSmall())) {
2699 : VisitUnop(node, UseInfo::AnyTagged(),
2700 0 : MachineRepresentation::kTaggedPointer);
2701 : } else {
2702 179304 : VisitUnop(node,
2703 : UseInfo::CheckedHeapObjectAsTaggedPointer(VectorSlotPair()),
2704 89652 : MachineRepresentation::kTaggedPointer);
2705 : }
2706 117891 : if (lower()) DeferReplacement(node, node->InputAt(0));
2707 : return;
2708 : }
2709 : case IrOpcode::kCheckIf: {
2710 51512 : ProcessInput(node, 0, UseInfo::Bool());
2711 51512 : ProcessRemainingInputs(node, 1);
2712 : SetOutput(node, MachineRepresentation::kNone);
2713 : return;
2714 : }
2715 : case IrOpcode::kCheckInternalizedString: {
2716 5558 : VisitCheck(node, Type::InternalizedString(), lowering);
2717 5558 : return;
2718 : }
2719 : case IrOpcode::kCheckNonEmptyString: {
2720 54 : VisitCheck(node, Type::NonEmptyString(), lowering);
2721 54 : return;
2722 : }
2723 : case IrOpcode::kCheckNonEmptyOneByteString: {
2724 5595 : VisitCheck(node, Type::NonEmptyOneByteString(), lowering);
2725 5595 : return;
2726 : }
2727 : case IrOpcode::kCheckNonEmptyTwoByteString: {
2728 730 : VisitCheck(node, Type::NonEmptyTwoByteString(), lowering);
2729 730 : return;
2730 : }
2731 : case IrOpcode::kCheckNumber: {
2732 1574 : Type const input_type = TypeOf(node->InputAt(0));
2733 1574 : if (input_type.Is(Type::Number())) {
2734 36 : VisitNoop(node, truncation);
2735 : } else {
2736 1538 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2737 : }
2738 : return;
2739 : }
2740 : case IrOpcode::kCheckReceiver: {
2741 3187 : VisitCheck(node, Type::Receiver(), lowering);
2742 3187 : return;
2743 : }
2744 : case IrOpcode::kCheckReceiverOrNullOrUndefined: {
2745 230 : VisitCheck(node, Type::ReceiverOrNullOrUndefined(), lowering);
2746 230 : return;
2747 : }
2748 : case IrOpcode::kCheckSmi: {
2749 97349 : const CheckParameters& params = CheckParametersOf(node->op());
2750 97349 : if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
2751 : VisitUnop(node,
2752 : UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros,
2753 : params.feedback()),
2754 24275 : MachineRepresentation::kWord32);
2755 : } else {
2756 : VisitUnop(
2757 : node,
2758 : UseInfo::CheckedSignedSmallAsTaggedSigned(params.feedback()),
2759 73074 : MachineRepresentation::kTaggedSigned);
2760 : }
2761 126860 : if (lower()) DeferReplacement(node, node->InputAt(0));
2762 : return;
2763 : }
2764 : case IrOpcode::kCheckString: {
2765 18891 : const CheckParameters& params = CheckParametersOf(node->op());
2766 18891 : if (InputIs(node, Type::String())) {
2767 : VisitUnop(node, UseInfo::AnyTagged(),
2768 0 : MachineRepresentation::kTaggedPointer);
2769 0 : if (lower()) DeferReplacement(node, node->InputAt(0));
2770 : } else {
2771 : VisitUnop(
2772 : node,
2773 : UseInfo::CheckedHeapObjectAsTaggedPointer(params.feedback()),
2774 18891 : MachineRepresentation::kTaggedPointer);
2775 : }
2776 : return;
2777 : }
2778 : case IrOpcode::kCheckSymbol: {
2779 104 : VisitCheck(node, Type::Symbol(), lowering);
2780 104 : return;
2781 : }
2782 :
2783 : case IrOpcode::kAllocate: {
2784 340725 : ProcessInput(node, 0, UseInfo::Word());
2785 340725 : ProcessRemainingInputs(node, 1);
2786 : SetOutput(node, MachineRepresentation::kTaggedPointer);
2787 : return;
2788 : }
2789 : case IrOpcode::kLoadMessage: {
2790 89616 : if (truncation.IsUnused()) return VisitUnused(node);
2791 21890 : VisitUnop(node, UseInfo::Word(), MachineRepresentation::kTagged);
2792 21890 : return;
2793 : }
2794 : case IrOpcode::kStoreMessage: {
2795 89999 : ProcessInput(node, 0, UseInfo::Word());
2796 89999 : ProcessInput(node, 1, UseInfo::AnyTagged());
2797 89999 : ProcessRemainingInputs(node, 2);
2798 : SetOutput(node, MachineRepresentation::kNone);
2799 : return;
2800 : }
2801 : case IrOpcode::kLoadFieldByIndex: {
2802 2107 : if (truncation.IsUnused()) return VisitUnused(node);
2803 : VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
2804 2073 : MachineRepresentation::kTagged);
2805 2073 : return;
2806 : }
2807 : case IrOpcode::kLoadField: {
2808 3863252 : if (truncation.IsUnused()) return VisitUnused(node);
2809 3752011 : FieldAccess access = FieldAccessOf(node->op());
2810 : MachineRepresentation const representation =
2811 : access.machine_type.representation();
2812 3752011 : VisitUnop(node, UseInfoForBasePointer(access), representation);
2813 3752015 : return;
2814 : }
2815 : case IrOpcode::kStoreField: {
2816 6276194 : FieldAccess access = FieldAccessOf(node->op());
2817 : Node* value_node = node->InputAt(1);
2818 : NodeInfo* input_info = GetInfo(value_node);
2819 : MachineRepresentation field_representation =
2820 : access.machine_type.representation();
2821 :
2822 : // Convert to Smi if possible, such that we can avoid a write barrier.
2823 18828588 : if (field_representation == MachineRepresentation::kTagged &&
2824 16381416 : TypeOf(value_node).Is(Type::SignedSmall())) {
2825 : field_representation = MachineRepresentation::kTaggedSigned;
2826 : }
2827 6276196 : WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2828 6276196 : access.base_is_tagged, field_representation, access.offset,
2829 : access.type, input_info->representation(), value_node);
2830 :
2831 6276194 : ProcessInput(node, 0, UseInfoForBasePointer(access));
2832 6276195 : ProcessInput(node, 1,
2833 6276197 : TruncatingUseInfoFromRepresentation(field_representation));
2834 6276194 : ProcessRemainingInputs(node, 2);
2835 : SetOutput(node, MachineRepresentation::kNone);
2836 6276196 : if (lower()) {
2837 2088814 : if (write_barrier_kind < access.write_barrier_kind) {
2838 723200 : access.write_barrier_kind = write_barrier_kind;
2839 723200 : NodeProperties::ChangeOp(
2840 1446400 : node, jsgraph_->simplified()->StoreField(access));
2841 : }
2842 : }
2843 : return;
2844 : }
2845 : case IrOpcode::kLoadElement: {
2846 64529 : if (truncation.IsUnused()) return VisitUnused(node);
2847 62412 : ElementAccess access = ElementAccessOf(node->op());
2848 62412 : VisitBinop(node, UseInfoForBasePointer(access), UseInfo::Word(),
2849 62412 : access.machine_type.representation());
2850 62412 : return;
2851 : }
2852 : case IrOpcode::kLoadStackArgument: {
2853 2346 : if (truncation.IsUnused()) return VisitUnused(node);
2854 : VisitBinop(node, UseInfo::Word(), MachineRepresentation::kTagged);
2855 : return;
2856 : }
2857 : case IrOpcode::kStoreElement: {
2858 119207 : ElementAccess access = ElementAccessOf(node->op());
2859 : Node* value_node = node->InputAt(2);
2860 : NodeInfo* input_info = GetInfo(value_node);
2861 : MachineRepresentation element_representation =
2862 : access.machine_type.representation();
2863 :
2864 : // Convert to Smi if possible, such that we can avoid a write barrier.
2865 357621 : if (element_representation == MachineRepresentation::kTagged &&
2866 275865 : TypeOf(value_node).Is(Type::SignedSmall())) {
2867 : element_representation = MachineRepresentation::kTaggedSigned;
2868 : }
2869 119207 : WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2870 119207 : access.base_is_tagged, element_representation, access.type,
2871 119207 : input_info->representation(), value_node);
2872 119207 : ProcessInput(node, 0, UseInfoForBasePointer(access)); // base
2873 119207 : ProcessInput(node, 1, UseInfo::Word()); // index
2874 119207 : ProcessInput(node, 2,
2875 : TruncatingUseInfoFromRepresentation(
2876 119207 : element_representation)); // value
2877 119207 : ProcessRemainingInputs(node, 3);
2878 : SetOutput(node, MachineRepresentation::kNone);
2879 119207 : if (lower()) {
2880 38886 : if (write_barrier_kind < access.write_barrier_kind) {
2881 22673 : access.write_barrier_kind = write_barrier_kind;
2882 22673 : NodeProperties::ChangeOp(
2883 45346 : node, jsgraph_->simplified()->StoreElement(access));
2884 : }
2885 : }
2886 : return;
2887 : }
2888 : case IrOpcode::kNumberIsFloat64Hole: {
2889 : VisitUnop(node, UseInfo::TruncatingFloat64(),
2890 230 : MachineRepresentation::kBit);
2891 230 : return;
2892 : }
2893 : case IrOpcode::kTransitionAndStoreElement: {
2894 878 : Type value_type = TypeOf(node->InputAt(2));
2895 :
2896 878 : ProcessInput(node, 0, UseInfo::AnyTagged()); // array
2897 878 : ProcessInput(node, 1, UseInfo::Word()); // index
2898 :
2899 878 : if (value_type.Is(Type::SignedSmall())) {
2900 287 : ProcessInput(node, 2, UseInfo::TruncatingWord32()); // value
2901 287 : if (lower()) {
2902 70 : NodeProperties::ChangeOp(node,
2903 70 : simplified()->StoreSignedSmallElement());
2904 : }
2905 591 : } else if (value_type.Is(Type::Number())) {
2906 123 : ProcessInput(node, 2, UseInfo::TruncatingFloat64()); // value
2907 123 : if (lower()) {
2908 28 : Handle<Map> double_map = DoubleMapParameterOf(node->op());
2909 28 : NodeProperties::ChangeOp(
2910 : node,
2911 28 : simplified()->TransitionAndStoreNumberElement(double_map));
2912 : }
2913 468 : } else if (value_type.Is(Type::NonNumber())) {
2914 92 : ProcessInput(node, 2, UseInfo::AnyTagged()); // value
2915 92 : if (lower()) {
2916 20 : Handle<Map> fast_map = FastMapParameterOf(node->op());
2917 20 : NodeProperties::ChangeOp(
2918 : node, simplified()->TransitionAndStoreNonNumberElement(
2919 20 : fast_map, value_type));
2920 : }
2921 : } else {
2922 376 : ProcessInput(node, 2, UseInfo::AnyTagged()); // value
2923 : }
2924 :
2925 878 : ProcessRemainingInputs(node, 3);
2926 : SetOutput(node, MachineRepresentation::kNone);
2927 : return;
2928 : }
2929 : case IrOpcode::kLoadTypedElement: {
2930 : MachineRepresentation const rep =
2931 16626 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2932 16626 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2933 16626 : ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2934 16626 : ProcessInput(node, 2, UseInfo::Word()); // external pointer
2935 16626 : ProcessInput(node, 3, UseInfo::Word()); // index
2936 16626 : ProcessRemainingInputs(node, 4);
2937 : SetOutput(node, rep);
2938 : return;
2939 : }
2940 : case IrOpcode::kLoadDataViewElement: {
2941 : MachineRepresentation const rep =
2942 804 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2943 804 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2944 804 : ProcessInput(node, 1, UseInfo::Word()); // external pointer
2945 804 : ProcessInput(node, 2, UseInfo::Word()); // byte offset
2946 804 : ProcessInput(node, 3, UseInfo::Word()); // index
2947 804 : ProcessInput(node, 4, UseInfo::Bool()); // little-endian
2948 804 : ProcessRemainingInputs(node, 5);
2949 : SetOutput(node, rep);
2950 : return;
2951 : }
2952 : case IrOpcode::kStoreTypedElement: {
2953 : MachineRepresentation const rep =
2954 15788 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2955 15788 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2956 15788 : ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2957 15788 : ProcessInput(node, 2, UseInfo::Word()); // external pointer
2958 15788 : ProcessInput(node, 3, UseInfo::Word()); // index
2959 15788 : ProcessInput(node, 4,
2960 15788 : TruncatingUseInfoFromRepresentation(rep)); // value
2961 15788 : ProcessRemainingInputs(node, 5);
2962 : SetOutput(node, MachineRepresentation::kNone);
2963 : return;
2964 : }
2965 : case IrOpcode::kStoreDataViewElement: {
2966 : MachineRepresentation const rep =
2967 588 : MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2968 588 : ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2969 588 : ProcessInput(node, 1, UseInfo::Word()); // external pointer
2970 588 : ProcessInput(node, 2, UseInfo::Word()); // byte offset
2971 588 : ProcessInput(node, 3, UseInfo::Word()); // index
2972 588 : ProcessInput(node, 4,
2973 588 : TruncatingUseInfoFromRepresentation(rep)); // value
2974 588 : ProcessInput(node, 5, UseInfo::Bool()); // little-endian
2975 588 : ProcessRemainingInputs(node, 6);
2976 : SetOutput(node, MachineRepresentation::kNone);
2977 : return;
2978 : }
2979 : case IrOpcode::kConvertReceiver: {
2980 2676 : Type input_type = TypeOf(node->InputAt(0));
2981 : VisitBinop(node, UseInfo::AnyTagged(),
2982 : MachineRepresentation::kTaggedPointer);
2983 2676 : if (lower()) {
2984 : // Try to optimize the {node} based on the input type.
2985 873 : if (input_type.Is(Type::Receiver())) {
2986 0 : DeferReplacement(node, node->InputAt(0));
2987 873 : } else if (input_type.Is(Type::NullOrUndefined())) {
2988 0 : DeferReplacement(node, node->InputAt(1));
2989 873 : } else if (!input_type.Maybe(Type::NullOrUndefined())) {
2990 85 : NodeProperties::ChangeOp(
2991 : node, lowering->simplified()->ConvertReceiver(
2992 85 : ConvertReceiverMode::kNotNullOrUndefined));
2993 : }
2994 : }
2995 : return;
2996 : }
2997 : case IrOpcode::kPlainPrimitiveToNumber: {
2998 2624 : if (InputIs(node, Type::Boolean())) {
2999 199 : VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32);
3000 258 : if (lower()) DeferReplacement(node, node->InputAt(0));
3001 2425 : } else if (InputIs(node, Type::String())) {
3002 1001 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3003 1001 : if (lower()) {
3004 331 : NodeProperties::ChangeOp(node, simplified()->StringToNumber());
3005 : }
3006 1424 : } else if (truncation.IsUsedAsWord32()) {
3007 57 : if (InputIs(node, Type::NumberOrOddball())) {
3008 : VisitUnop(node, UseInfo::TruncatingWord32(),
3009 30 : MachineRepresentation::kWord32);
3010 40 : if (lower()) DeferReplacement(node, node->InputAt(0));
3011 : } else {
3012 : VisitUnop(node, UseInfo::AnyTagged(),
3013 27 : MachineRepresentation::kWord32);
3014 27 : if (lower()) {
3015 9 : NodeProperties::ChangeOp(node,
3016 9 : simplified()->PlainPrimitiveToWord32());
3017 : }
3018 : }
3019 1367 : } else if (truncation.IsUsedAsFloat64()) {
3020 1291 : if (InputIs(node, Type::NumberOrOddball())) {
3021 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3022 1291 : MachineRepresentation::kFloat64);
3023 1623 : if (lower()) DeferReplacement(node, node->InputAt(0));
3024 : } else {
3025 : VisitUnop(node, UseInfo::AnyTagged(),
3026 0 : MachineRepresentation::kFloat64);
3027 0 : if (lower()) {
3028 0 : NodeProperties::ChangeOp(node,
3029 0 : simplified()->PlainPrimitiveToFloat64());
3030 : }
3031 : }
3032 : } else {
3033 76 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3034 : }
3035 : return;
3036 : }
3037 : case IrOpcode::kSpeculativeToNumber: {
3038 : NumberOperationParameters const& p =
3039 133175 : NumberOperationParametersOf(node->op());
3040 133175 : switch (p.hint()) {
3041 : case NumberOperationHint::kSigned32:
3042 : case NumberOperationHint::kSignedSmall:
3043 : case NumberOperationHint::kSignedSmallInputs:
3044 6203 : VisitUnop(node,
3045 : CheckedUseInfoAsWord32FromHint(p.hint(), p.feedback()),
3046 6203 : MachineRepresentation::kWord32, Type::Signed32());
3047 6203 : break;
3048 : case NumberOperationHint::kNumber:
3049 : case NumberOperationHint::kNumberOrOddball:
3050 126972 : VisitUnop(node,
3051 : CheckedUseInfoAsFloat64FromHint(p.hint(), p.feedback()),
3052 126972 : MachineRepresentation::kFloat64);
3053 126972 : break;
3054 : }
3055 173513 : if (lower()) DeferReplacement(node, node->InputAt(0));
3056 : return;
3057 : }
3058 : case IrOpcode::kObjectIsArrayBufferView: {
3059 : // TODO(turbofan): Introduce a Type::ArrayBufferView?
3060 48 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3061 48 : return;
3062 : }
3063 : case IrOpcode::kObjectIsBigInt: {
3064 75 : VisitObjectIs(node, Type::BigInt(), lowering);
3065 75 : return;
3066 : }
3067 : case IrOpcode::kObjectIsCallable: {
3068 330 : VisitObjectIs(node, Type::Callable(), lowering);
3069 330 : return;
3070 : }
3071 : case IrOpcode::kObjectIsConstructor: {
3072 : // TODO(turbofan): Introduce a Type::Constructor?
3073 1131 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3074 1131 : return;
3075 : }
3076 : case IrOpcode::kObjectIsDetectableCallable: {
3077 43900 : VisitObjectIs(node, Type::DetectableCallable(), lowering);
3078 43900 : return;
3079 : }
3080 : case IrOpcode::kObjectIsFiniteNumber: {
3081 588 : Type const input_type = GetUpperBound(node->InputAt(0));
3082 1176 : if (input_type.Is(type_cache_->kSafeInteger)) {
3083 210 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3084 210 : if (lower()) {
3085 70 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3086 : }
3087 378 : } else if (!input_type.Maybe(Type::Number())) {
3088 42 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3089 42 : if (lower()) {
3090 14 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3091 : }
3092 336 : } else if (input_type.Is(Type::Number())) {
3093 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3094 315 : MachineRepresentation::kBit);
3095 315 : if (lower()) {
3096 105 : NodeProperties::ChangeOp(node,
3097 105 : lowering->simplified()->NumberIsFinite());
3098 : }
3099 : } else {
3100 21 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3101 : }
3102 : return;
3103 : }
3104 : case IrOpcode::kNumberIsFinite: {
3105 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3106 70 : MachineRepresentation::kBit);
3107 70 : return;
3108 : }
3109 : case IrOpcode::kObjectIsSafeInteger: {
3110 42 : Type const input_type = GetUpperBound(node->InputAt(0));
3111 84 : if (input_type.Is(type_cache_->kSafeInteger)) {
3112 0 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3113 0 : if (lower()) {
3114 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3115 : }
3116 42 : } else if (!input_type.Maybe(Type::Number())) {
3117 0 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3118 0 : if (lower()) {
3119 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3120 : }
3121 42 : } else if (input_type.Is(Type::Number())) {
3122 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3123 21 : MachineRepresentation::kBit);
3124 21 : if (lower()) {
3125 7 : NodeProperties::ChangeOp(
3126 7 : node, lowering->simplified()->NumberIsSafeInteger());
3127 : }
3128 : } else {
3129 21 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3130 : }
3131 : return;
3132 : }
3133 : case IrOpcode::kNumberIsSafeInteger: {
3134 0 : UNREACHABLE();
3135 : }
3136 : case IrOpcode::kObjectIsInteger: {
3137 588 : Type const input_type = GetUpperBound(node->InputAt(0));
3138 1176 : if (input_type.Is(type_cache_->kSafeInteger)) {
3139 210 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3140 210 : if (lower()) {
3141 70 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3142 : }
3143 378 : } else if (!input_type.Maybe(Type::Number())) {
3144 0 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3145 0 : if (lower()) {
3146 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3147 : }
3148 378 : } else if (input_type.Is(Type::Number())) {
3149 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3150 357 : MachineRepresentation::kBit);
3151 357 : if (lower()) {
3152 119 : NodeProperties::ChangeOp(node,
3153 119 : lowering->simplified()->NumberIsInteger());
3154 : }
3155 : } else {
3156 21 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3157 : }
3158 : return;
3159 : }
3160 : case IrOpcode::kNumberIsInteger: {
3161 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3162 0 : MachineRepresentation::kBit);
3163 0 : return;
3164 : }
3165 : case IrOpcode::kObjectIsMinusZero: {
3166 363 : Type const input_type = GetUpperBound(node->InputAt(0));
3167 363 : if (input_type.Is(Type::MinusZero())) {
3168 0 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3169 0 : if (lower()) {
3170 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3171 : }
3172 363 : } else if (!input_type.Maybe(Type::MinusZero())) {
3173 0 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3174 0 : if (lower()) {
3175 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3176 : }
3177 363 : } else if (input_type.Is(Type::Number())) {
3178 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3179 294 : MachineRepresentation::kBit);
3180 294 : if (lower()) {
3181 98 : NodeProperties::ChangeOp(node, simplified()->NumberIsMinusZero());
3182 : }
3183 : } else {
3184 69 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3185 : }
3186 : return;
3187 : }
3188 : case IrOpcode::kObjectIsNaN: {
3189 2724 : Type const input_type = GetUpperBound(node->InputAt(0));
3190 2724 : if (input_type.Is(Type::NaN())) {
3191 0 : VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
3192 0 : if (lower()) {
3193 0 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3194 : }
3195 2724 : } else if (!input_type.Maybe(Type::NaN())) {
3196 36 : VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit);
3197 36 : if (lower()) {
3198 12 : DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3199 : }
3200 2688 : } else if (input_type.Is(Type::Number())) {
3201 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3202 540 : MachineRepresentation::kBit);
3203 540 : if (lower()) {
3204 180 : NodeProperties::ChangeOp(node, simplified()->NumberIsNaN());
3205 : }
3206 : } else {
3207 2148 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3208 : }
3209 : return;
3210 : }
3211 : case IrOpcode::kNumberIsNaN: {
3212 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3213 8464 : MachineRepresentation::kBit);
3214 8464 : return;
3215 : }
3216 : case IrOpcode::kObjectIsNonCallable: {
3217 18705 : VisitObjectIs(node, Type::NonCallable(), lowering);
3218 18705 : return;
3219 : }
3220 : case IrOpcode::kObjectIsNumber: {
3221 23541 : VisitObjectIs(node, Type::Number(), lowering);
3222 23541 : return;
3223 : }
3224 : case IrOpcode::kObjectIsReceiver: {
3225 64029 : VisitObjectIs(node, Type::Receiver(), lowering);
3226 64029 : return;
3227 : }
3228 : case IrOpcode::kObjectIsSmi: {
3229 : // TODO(turbofan): Optimize based on input representation.
3230 3935 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3231 3935 : return;
3232 : }
3233 : case IrOpcode::kObjectIsString: {
3234 7026 : VisitObjectIs(node, Type::String(), lowering);
3235 7026 : return;
3236 : }
3237 : case IrOpcode::kObjectIsSymbol: {
3238 71 : VisitObjectIs(node, Type::Symbol(), lowering);
3239 71 : return;
3240 : }
3241 : case IrOpcode::kObjectIsUndetectable: {
3242 4845 : VisitObjectIs(node, Type::Undetectable(), lowering);
3243 4845 : return;
3244 : }
3245 : case IrOpcode::kArgumentsFrame: {
3246 : SetOutput(node, MachineType::PointerRepresentation());
3247 : return;
3248 : }
3249 : case IrOpcode::kArgumentsLength: {
3250 50936 : VisitUnop(node, UseInfo::Word(), MachineRepresentation::kTaggedSigned);
3251 50936 : return;
3252 : }
3253 : case IrOpcode::kNewDoubleElements:
3254 : case IrOpcode::kNewSmiOrObjectElements: {
3255 1662 : VisitUnop(node, UseInfo::Word(), MachineRepresentation::kTaggedPointer);
3256 1662 : return;
3257 : }
3258 : case IrOpcode::kNewArgumentsElements: {
3259 : VisitBinop(node, UseInfo::Word(), UseInfo::TaggedSigned(),
3260 58963 : MachineRepresentation::kTaggedPointer);
3261 58963 : return;
3262 : }
3263 : case IrOpcode::kCheckFloat64Hole: {
3264 1903 : Type const input_type = TypeOf(node->InputAt(0));
3265 : CheckFloat64HoleMode mode =
3266 1903 : CheckFloat64HoleParametersOf(node->op()).mode();
3267 1903 : if (mode == CheckFloat64HoleMode::kAllowReturnHole) {
3268 : // If {mode} is allow-return-hole _and_ the {truncation}
3269 : // identifies NaN and undefined, we can just pass along
3270 : // the {truncation} and completely wipe the {node}.
3271 1358 : if (truncation.IsUnused()) return VisitUnused(node);
3272 1262 : if (truncation.IsUsedAsFloat64()) {
3273 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3274 129 : MachineRepresentation::kFloat64);
3275 172 : if (lower()) DeferReplacement(node, node->InputAt(0));
3276 : return;
3277 : }
3278 : }
3279 3356 : VisitUnop(node,
3280 : UseInfo(MachineRepresentation::kFloat64, Truncation::Any()),
3281 1678 : MachineRepresentation::kFloat64, Type::Number());
3282 2216 : if (lower() && input_type.Is(Type::Number())) {
3283 64 : DeferReplacement(node, node->InputAt(0));
3284 : }
3285 : return;
3286 : }
3287 : case IrOpcode::kCheckNotTaggedHole: {
3288 330 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3289 330 : return;
3290 : }
3291 : case IrOpcode::kConvertTaggedHoleToUndefined: {
3292 10258 : if (InputIs(node, Type::NumberOrOddball()) &&
3293 : truncation.IsUsedAsWord32()) {
3294 : // Propagate the Word32 truncation.
3295 : VisitUnop(node, UseInfo::TruncatingWord32(),
3296 1009 : MachineRepresentation::kWord32);
3297 1259 : if (lower()) DeferReplacement(node, node->InputAt(0));
3298 8240 : } else if (InputIs(node, Type::NumberOrOddball()) &&
3299 : truncation.IsUsedAsFloat64()) {
3300 : // Propagate the Float64 truncation.
3301 : VisitUnop(node, UseInfo::TruncatingFloat64(),
3302 143 : MachineRepresentation::kFloat64);
3303 187 : if (lower()) DeferReplacement(node, node->InputAt(0));
3304 6078 : } else if (InputIs(node, Type::NonInternal())) {
3305 126 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3306 168 : if (lower()) DeferReplacement(node, node->InputAt(0));
3307 : } else {
3308 : // TODO(turbofan): Add a (Tagged) truncation that identifies hole
3309 : // and undefined, i.e. for a[i] === obj cases.
3310 5952 : VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
3311 : }
3312 : return;
3313 : }
3314 : case IrOpcode::kCheckEqualsSymbol:
3315 : case IrOpcode::kCheckEqualsInternalizedString:
3316 : return VisitBinop(node, UseInfo::AnyTagged(),
3317 : MachineRepresentation::kNone);
3318 : case IrOpcode::kMapGuard:
3319 : // Eliminate MapGuard nodes here.
3320 22210 : return VisitUnused(node);
3321 : case IrOpcode::kCheckMaps:
3322 : case IrOpcode::kTransitionElementsKind: {
3323 162727 : VisitInputs(node);
3324 : return SetOutput(node, MachineRepresentation::kNone);
3325 : }
3326 : case IrOpcode::kCompareMaps:
3327 : return VisitUnop(node, UseInfo::AnyTagged(),
3328 24141 : MachineRepresentation::kBit);
3329 : case IrOpcode::kEnsureWritableFastElements:
3330 : return VisitBinop(node, UseInfo::AnyTagged(),
3331 : MachineRepresentation::kTaggedPointer);
3332 : case IrOpcode::kMaybeGrowFastElements: {
3333 11509 : Type const index_type = TypeOf(node->InputAt(2));
3334 11509 : Type const length_type = TypeOf(node->InputAt(3));
3335 11509 : ProcessInput(node, 0, UseInfo::AnyTagged()); // object
3336 11509 : ProcessInput(node, 1, UseInfo::AnyTagged()); // elements
3337 11509 : ProcessInput(node, 2, UseInfo::TruncatingWord32()); // index
3338 11509 : ProcessInput(node, 3, UseInfo::TruncatingWord32()); // length
3339 11509 : ProcessRemainingInputs(node, 4);
3340 : SetOutput(node, MachineRepresentation::kTaggedPointer);
3341 11509 : if (lower()) {
3342 : // If the index is known to be less than the length (or if
3343 : // we're in dead code), we know that we don't need to grow
3344 : // the elements, so we can just remove this operation all
3345 : // together and replace it with the elements that we have
3346 : // on the inputs.
3347 10629 : if (index_type.IsNone() || length_type.IsNone() ||
3348 3543 : index_type.Max() < length_type.Min()) {
3349 50 : DeferReplacement(node, node->InputAt(1));
3350 : }
3351 : }
3352 : return;
3353 : }
3354 :
3355 : case IrOpcode::kDateNow:
3356 39 : VisitInputs(node);
3357 : return SetOutput(node, MachineRepresentation::kTaggedPointer);
3358 : case IrOpcode::kFrameState:
3359 16622413 : return VisitFrameState(node);
3360 : case IrOpcode::kStateValues:
3361 10996380 : return VisitStateValues(node);
3362 : case IrOpcode::kObjectState:
3363 69405 : return VisitObjectState(node);
3364 : case IrOpcode::kObjectId:
3365 : return SetOutput(node, MachineRepresentation::kTaggedPointer);
3366 : case IrOpcode::kTypeGuard: {
3367 : // We just get rid of the sigma here, choosing the best representation
3368 : // for the sigma's type.
3369 91589 : Type type = TypeOf(node);
3370 : MachineRepresentation representation =
3371 91589 : GetOutputInfoForPhi(node, type, truncation);
3372 :
3373 : // Here we pretend that the input has the sigma's type for the
3374 : // conversion.
3375 183183 : UseInfo use(representation, truncation);
3376 91591 : if (propagate()) {
3377 30741 : EnqueueInput(node, 0, use);
3378 60850 : } else if (lower()) {
3379 22678 : ConvertInput(node, 0, use, type);
3380 : }
3381 91592 : ProcessRemainingInputs(node, 1);
3382 : SetOutput(node, representation);
3383 : return;
3384 : }
3385 :
3386 : case IrOpcode::kFinishRegion:
3387 405141 : VisitInputs(node);
3388 : // Assume the output is tagged pointer.
3389 : return SetOutput(node, MachineRepresentation::kTaggedPointer);
3390 :
3391 : case IrOpcode::kReturn:
3392 1671273 : VisitReturn(node);
3393 : // Assume the output is tagged.
3394 : return SetOutput(node, MachineRepresentation::kTagged);
3395 :
3396 : case IrOpcode::kFindOrderedHashMapEntry: {
3397 684 : Type const key_type = TypeOf(node->InputAt(1));
3398 684 : if (key_type.Is(Type::Signed32OrMinusZero())) {
3399 : VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
3400 64 : MachineType::PointerRepresentation());
3401 64 : if (lower()) {
3402 16 : NodeProperties::ChangeOp(
3403 : node,
3404 16 : lowering->simplified()->FindOrderedHashMapEntryForInt32Key());
3405 : }
3406 : } else {
3407 : VisitBinop(node, UseInfo::AnyTagged(),
3408 : MachineRepresentation::kTaggedSigned);
3409 : }
3410 : return;
3411 : }
3412 :
3413 : // Operators with all inputs tagged and no or tagged output have uniform
3414 : // handling.
3415 : case IrOpcode::kEnd:
3416 : case IrOpcode::kIfSuccess:
3417 : case IrOpcode::kIfException:
3418 : case IrOpcode::kIfTrue:
3419 : case IrOpcode::kIfFalse:
3420 : case IrOpcode::kIfValue:
3421 : case IrOpcode::kIfDefault:
3422 : case IrOpcode::kDeoptimize:
3423 : case IrOpcode::kEffectPhi:
3424 : case IrOpcode::kTerminate:
3425 : case IrOpcode::kCheckpoint:
3426 : case IrOpcode::kLoop:
3427 : case IrOpcode::kMerge:
3428 : case IrOpcode::kThrow:
3429 : case IrOpcode::kBeginRegion:
3430 : case IrOpcode::kProjection:
3431 : case IrOpcode::kOsrValue:
3432 : case IrOpcode::kArgumentsElementsState:
3433 : case IrOpcode::kArgumentsLengthState:
3434 : case IrOpcode::kUnreachable:
3435 : case IrOpcode::kRuntimeAbort:
3436 : // All JavaScript operators except JSToNumber have uniform handling.
3437 : #define OPCODE_CASE(name) case IrOpcode::k##name:
3438 : JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
3439 : JS_OBJECT_OP_LIST(OPCODE_CASE)
3440 : JS_CONTEXT_OP_LIST(OPCODE_CASE)
3441 : JS_OTHER_OP_LIST(OPCODE_CASE)
3442 : #undef OPCODE_CASE
3443 : case IrOpcode::kJSBitwiseNot:
3444 : case IrOpcode::kJSDecrement:
3445 : case IrOpcode::kJSIncrement:
3446 : case IrOpcode::kJSNegate:
3447 : case IrOpcode::kJSToLength:
3448 : case IrOpcode::kJSToName:
3449 : case IrOpcode::kJSToObject:
3450 : case IrOpcode::kJSToString:
3451 : case IrOpcode::kJSParseInt:
3452 29093954 : VisitInputs(node);
3453 : // Assume the output is tagged.
3454 : return SetOutput(node, MachineRepresentation::kTagged);
3455 : case IrOpcode::kDeadValue:
3456 1616 : ProcessInput(node, 0, UseInfo::Any());
3457 : return SetOutput(node, MachineRepresentation::kNone);
3458 : default:
3459 0 : FATAL(
3460 : "Representation inference: unsupported opcode %i (%s), node #%i\n.",
3461 0 : node->opcode(), node->op()->mnemonic(), node->id());
3462 : break;
3463 : }
3464 : UNREACHABLE();
3465 : }
3466 :
3467 1260703 : void DeferReplacement(Node* node, Node* replacement) {
3468 1260703 : TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
3469 : node->op()->mnemonic(), replacement->id(),
3470 : replacement->op()->mnemonic());
3471 :
3472 : // Disconnect the node from effect and control chains, if necessary.
3473 2521414 : if (node->op()->EffectInputCount() > 0) {
3474 : DCHECK_LT(0, node->op()->ControlInputCount());
3475 : // Disconnect the node from effect and control chains.
3476 105837 : Node* control = NodeProperties::GetControlInput(node);
3477 105837 : Node* effect = NodeProperties::GetEffectInput(node);
3478 105837 : ReplaceEffectControlUses(node, effect, control);
3479 : }
3480 :
3481 1260707 : replacements_.push_back(node);
3482 1260707 : replacements_.push_back(replacement);
3483 :
3484 1260708 : node->NullAllInputs(); // Node is now dead.
3485 1260706 : }
3486 :
3487 34319 : void Kill(Node* node) {
3488 34319 : TRACE("killing #%d:%s\n", node->id(), node->op()->mnemonic());
3489 :
3490 34319 : if (node->op()->EffectInputCount() == 1) {
3491 : DCHECK_LT(0, node->op()->ControlInputCount());
3492 : // Disconnect the node from effect and control chains.
3493 34305 : Node* control = NodeProperties::GetControlInput(node);
3494 34305 : Node* effect = NodeProperties::GetEffectInput(node);
3495 34305 : ReplaceEffectControlUses(node, effect, control);
3496 : } else {
3497 : DCHECK_EQ(0, node->op()->EffectInputCount());
3498 : DCHECK_EQ(0, node->op()->ControlOutputCount());
3499 : DCHECK_EQ(0, node->op()->EffectOutputCount());
3500 : }
3501 :
3502 34319 : node->ReplaceUses(jsgraph_->Dead());
3503 :
3504 34319 : node->NullAllInputs(); // The {node} is now dead.
3505 34319 : }
3506 :
3507 51627441 : void PrintOutputInfo(NodeInfo* info) {
3508 51627441 : if (FLAG_trace_representation) {
3509 0 : StdoutStream{} << info->representation();
3510 : }
3511 51627441 : }
3512 :
3513 : void PrintRepresentation(MachineRepresentation rep) {
3514 : if (FLAG_trace_representation) {
3515 : StdoutStream{} << rep;
3516 : }
3517 : }
3518 :
3519 102483362 : void PrintTruncation(Truncation truncation) {
3520 102483362 : if (FLAG_trace_representation) {
3521 0 : StdoutStream{} << truncation.description() << std::endl;
3522 : }
3523 102483362 : }
3524 :
3525 16065165 : void PrintUseInfo(UseInfo info) {
3526 16065165 : if (FLAG_trace_representation) {
3527 0 : StdoutStream{} << info.representation() << ":"
3528 0 : << info.truncation().description();
3529 : }
3530 16065165 : }
3531 :
3532 : private:
3533 : JSGraph* jsgraph_;
3534 : Zone* zone_; // Temporary zone.
3535 : size_t const count_; // number of nodes in the graph
3536 : ZoneVector<NodeInfo> info_; // node id -> usage information
3537 : #ifdef DEBUG
3538 : ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
3539 : // requirements on inputs.
3540 : #endif // DEBUG
3541 : NodeVector nodes_; // collected nodes
3542 : NodeVector replacements_; // replacements to be done after lowering
3543 : Phase phase_; // current phase of algorithm
3544 : RepresentationChanger* changer_; // for inserting representation changes
3545 : ZoneQueue<Node*> queue_; // queue for traversing the graph
3546 :
3547 : struct NodeState {
3548 : Node* node;
3549 : int input_index;
3550 : };
3551 : ZoneStack<NodeState> typing_stack_; // stack for graph typing.
3552 : // TODO(danno): RepresentationSelector shouldn't know anything about the
3553 : // source positions table, but must for now since there currently is no other
3554 : // way to pass down source position information to nodes created during
3555 : // lowering. Once this phase becomes a vanilla reducer, it should get source
3556 : // position information via the SourcePositionWrapper like all other reducers.
3557 : SourcePositionTable* source_positions_;
3558 : NodeOriginTable* node_origins_;
3559 : TypeCache const* type_cache_;
3560 : OperationTyper op_typer_; // helper for the feedback typer
3561 :
3562 : NodeInfo* GetInfo(Node* node) {
3563 : DCHECK(node->id() < count_);
3564 705027723 : return &info_[node->id()];
3565 : }
3566 : Zone* zone() { return zone_; }
3567 : Zone* graph_zone() { return jsgraph_->zone(); }
3568 : };
3569 :
3570 464173 : SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker,
3571 : Zone* zone,
3572 : SourcePositionTable* source_positions,
3573 : NodeOriginTable* node_origins,
3574 : PoisoningMitigationLevel poisoning_level)
3575 : : jsgraph_(jsgraph),
3576 : broker_(broker),
3577 : zone_(zone),
3578 464173 : type_cache_(TypeCache::Get()),
3579 : source_positions_(source_positions),
3580 : node_origins_(node_origins),
3581 1392533 : poisoning_level_(poisoning_level) {}
3582 :
3583 464174 : void SimplifiedLowering::LowerAllNodes() {
3584 464174 : RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
3585 464177 : RepresentationSelector selector(jsgraph(), broker_, zone_, &changer,
3586 928354 : source_positions_, node_origins_);
3587 464181 : selector.Run(this);
3588 464180 : }
3589 :
3590 1413 : void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
3591 : Node* node, RepresentationSelector* selector) {
3592 : DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
3593 : node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
3594 : node->opcode() == IrOpcode::kJSToNumeric);
3595 : Node* value = node->InputAt(0);
3596 : Node* context = node->InputAt(1);
3597 : Node* frame_state = node->InputAt(2);
3598 : Node* effect = node->InputAt(3);
3599 : Node* control = node->InputAt(4);
3600 :
3601 1413 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
3602 : Node* branch0 =
3603 1413 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
3604 :
3605 1413 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3606 : Node* etrue0 = effect;
3607 : Node* vtrue0;
3608 : {
3609 1413 : vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
3610 1413 : vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
3611 : }
3612 :
3613 1413 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3614 : Node* efalse0 = effect;
3615 : Node* vfalse0;
3616 : {
3617 : Operator const* op =
3618 : node->opcode() == IrOpcode::kJSToNumber
3619 : ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3620 : ? ToNumberConvertBigIntOperator()
3621 : : ToNumberOperator())
3622 1413 : : ToNumericOperator();
3623 : Node* code = node->opcode() == IrOpcode::kJSToNumber
3624 : ? ToNumberCode()
3625 : : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3626 : ? ToNumberConvertBigIntCode()
3627 1413 : : ToNumericCode());
3628 : vfalse0 = efalse0 = if_false0 = graph()->NewNode(
3629 : op, code, value, context, frame_state, efalse0, if_false0);
3630 :
3631 : // Update potential {IfException} uses of {node} to point to the above
3632 : // stub call node instead.
3633 1413 : Node* on_exception = nullptr;
3634 1413 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3635 0 : NodeProperties::ReplaceControlInput(on_exception, vfalse0);
3636 0 : NodeProperties::ReplaceEffectInput(on_exception, efalse0);
3637 0 : if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
3638 : }
3639 :
3640 1413 : Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
3641 1413 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3642 :
3643 1413 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3644 : Node* etrue1 = efalse0;
3645 : Node* vtrue1;
3646 : {
3647 : vtrue1 =
3648 1413 : graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
3649 1413 : vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
3650 : }
3651 :
3652 1413 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3653 : Node* efalse1 = efalse0;
3654 : Node* vfalse1;
3655 : {
3656 1413 : vfalse1 = efalse1 = graph()->NewNode(
3657 2826 : simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
3658 : efalse1, if_false1);
3659 : }
3660 :
3661 1413 : if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
3662 : efalse0 =
3663 1413 : graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
3664 : vfalse0 =
3665 1413 : graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
3666 : vtrue1, vfalse1, if_false0);
3667 : }
3668 :
3669 1413 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
3670 1413 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
3671 1413 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
3672 : vtrue0, vfalse0, control);
3673 :
3674 : // Replace effect and control uses appropriately.
3675 9893 : for (Edge edge : node->use_edges()) {
3676 4240 : if (NodeProperties::IsControlEdge(edge)) {
3677 1413 : if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
3678 0 : edge.from()->ReplaceUses(control);
3679 0 : edge.from()->Kill();
3680 : } else {
3681 : DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
3682 1413 : edge.UpdateTo(control);
3683 : }
3684 2827 : } else if (NodeProperties::IsEffectEdge(edge)) {
3685 1414 : edge.UpdateTo(effect);
3686 : }
3687 : }
3688 :
3689 1413 : selector->DeferReplacement(node, value);
3690 1413 : }
3691 :
3692 75 : void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
3693 : Node* node, RepresentationSelector* selector) {
3694 : DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
3695 : node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
3696 : node->opcode() == IrOpcode::kJSToNumeric);
3697 : Node* value = node->InputAt(0);
3698 : Node* context = node->InputAt(1);
3699 : Node* frame_state = node->InputAt(2);
3700 : Node* effect = node->InputAt(3);
3701 : Node* control = node->InputAt(4);
3702 :
3703 75 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
3704 : Node* branch0 =
3705 75 : graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
3706 :
3707 75 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3708 : Node* etrue0 = effect;
3709 : Node* vtrue0 =
3710 75 : graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
3711 :
3712 75 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3713 : Node* efalse0 = effect;
3714 : Node* vfalse0;
3715 : {
3716 : Operator const* op =
3717 : node->opcode() == IrOpcode::kJSToNumber
3718 : ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3719 : ? ToNumberConvertBigIntOperator()
3720 : : ToNumberOperator())
3721 75 : : ToNumericOperator();
3722 : Node* code = node->opcode() == IrOpcode::kJSToNumber
3723 : ? ToNumberCode()
3724 : : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
3725 : ? ToNumberConvertBigIntCode()
3726 75 : : ToNumericCode());
3727 : vfalse0 = efalse0 = if_false0 = graph()->NewNode(
3728 : op, code, value, context, frame_state, efalse0, if_false0);
3729 :
3730 : // Update potential {IfException} uses of {node} to point to the above
3731 : // stub call node instead.
3732 75 : Node* on_exception = nullptr;
3733 75 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
3734 8 : NodeProperties::ReplaceControlInput(on_exception, vfalse0);
3735 8 : NodeProperties::ReplaceEffectInput(on_exception, efalse0);
3736 8 : if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
3737 : }
3738 :
3739 75 : Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
3740 75 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3741 :
3742 75 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3743 : Node* etrue1 = efalse0;
3744 : Node* vtrue1 =
3745 75 : graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
3746 :
3747 75 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3748 : Node* efalse1 = efalse0;
3749 : Node* vfalse1;
3750 : {
3751 75 : vfalse1 = efalse1 = graph()->NewNode(
3752 150 : simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
3753 : efalse1, if_false1);
3754 75 : vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
3755 : }
3756 :
3757 75 : if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
3758 : efalse0 =
3759 75 : graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
3760 75 : vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
3761 : vtrue1, vfalse1, if_false0);
3762 : }
3763 :
3764 75 : control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
3765 75 : effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
3766 75 : value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
3767 : vtrue0, vfalse0, control);
3768 :
3769 : // Replace effect and control uses appropriately.
3770 459 : for (Edge edge : node->use_edges()) {
3771 192 : if (NodeProperties::IsControlEdge(edge)) {
3772 114 : if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
3773 8 : edge.from()->ReplaceUses(control);
3774 8 : edge.from()->Kill();
3775 : } else {
3776 : DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
3777 106 : edge.UpdateTo(control);
3778 : }
3779 78 : } else if (NodeProperties::IsEffectEdge(edge)) {
3780 75 : edge.UpdateTo(effect);
3781 : }
3782 : }
3783 :
3784 75 : selector->DeferReplacement(node, value);
3785 75 : }
3786 :
3787 1554 : Node* SimplifiedLowering::Float64Round(Node* const node) {
3788 1554 : Node* const one = jsgraph()->Float64Constant(1.0);
3789 1554 : Node* const one_half = jsgraph()->Float64Constant(0.5);
3790 : Node* const input = node->InputAt(0);
3791 :
3792 : // Round up towards Infinity, and adjust if the difference exceeds 0.5.
3793 3108 : Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
3794 : node->InputAt(0));
3795 6216 : return graph()->NewNode(
3796 : common()->Select(MachineRepresentation::kFloat64),
3797 : graph()->NewNode(
3798 : machine()->Float64LessThanOrEqual(),
3799 : graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
3800 1554 : result, graph()->NewNode(machine()->Float64Sub(), result, one));
3801 : }
3802 :
3803 30 : Node* SimplifiedLowering::Float64Sign(Node* const node) {
3804 30 : Node* const minus_one = jsgraph()->Float64Constant(-1.0);
3805 30 : Node* const zero = jsgraph()->Float64Constant(0.0);
3806 30 : Node* const one = jsgraph()->Float64Constant(1.0);
3807 :
3808 : Node* const input = node->InputAt(0);
3809 :
3810 120 : return graph()->NewNode(
3811 : common()->Select(MachineRepresentation::kFloat64),
3812 : graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
3813 : graph()->NewNode(
3814 : common()->Select(MachineRepresentation::kFloat64),
3815 : graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
3816 30 : input));
3817 : }
3818 :
3819 83 : Node* SimplifiedLowering::Int32Abs(Node* const node) {
3820 : Node* const input = node->InputAt(0);
3821 :
3822 : // Generate case for absolute integer value.
3823 : //
3824 : // let sign = input >> 31 in
3825 : // (input ^ sign) - sign
3826 :
3827 83 : Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
3828 : jsgraph()->Int32Constant(31));
3829 166 : return graph()->NewNode(machine()->Int32Sub(),
3830 : graph()->NewNode(machine()->Word32Xor(), input, sign),
3831 83 : sign);
3832 : }
3833 :
3834 3007 : Node* SimplifiedLowering::Int32Div(Node* const node) {
3835 3007 : Int32BinopMatcher m(node);
3836 3007 : Node* const zero = jsgraph()->Int32Constant(0);
3837 3007 : Node* const minus_one = jsgraph()->Int32Constant(-1);
3838 : Node* const lhs = m.left().node();
3839 : Node* const rhs = m.right().node();
3840 :
3841 3007 : if (m.right().Is(-1)) {
3842 30 : return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3843 2992 : } else if (m.right().Is(0)) {
3844 : return rhs;
3845 2992 : } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
3846 4706 : return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
3847 : }
3848 :
3849 : // General case for signed integer division.
3850 : //
3851 : // if 0 < rhs then
3852 : // lhs / rhs
3853 : // else
3854 : // if rhs < -1 then
3855 : // lhs / rhs
3856 : // else if rhs == 0 then
3857 : // 0
3858 : // else
3859 : // 0 - lhs
3860 : //
3861 : // Note: We do not use the Diamond helper class here, because it really hurts
3862 : // readability with nested diamonds.
3863 639 : const Operator* const merge_op = common()->Merge(2);
3864 : const Operator* const phi_op =
3865 639 : common()->Phi(MachineRepresentation::kWord32, 2);
3866 :
3867 639 : Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3868 639 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3869 : graph()->start());
3870 :
3871 639 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3872 639 : Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
3873 :
3874 639 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3875 : Node* false0;
3876 : {
3877 639 : Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3878 639 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3879 :
3880 639 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3881 639 : Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
3882 :
3883 639 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3884 : Node* false1;
3885 : {
3886 639 : Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3887 639 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
3888 :
3889 639 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3890 : Node* true2 = zero;
3891 :
3892 639 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3893 639 : Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3894 :
3895 : if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3896 : false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3897 : }
3898 :
3899 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3900 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3901 : }
3902 :
3903 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3904 639 : return graph()->NewNode(phi_op, true0, false0, merge0);
3905 : }
3906 :
3907 2411 : Node* SimplifiedLowering::Int32Mod(Node* const node) {
3908 2411 : Int32BinopMatcher m(node);
3909 2411 : Node* const zero = jsgraph()->Int32Constant(0);
3910 2411 : Node* const minus_one = jsgraph()->Int32Constant(-1);
3911 : Node* const lhs = m.left().node();
3912 : Node* const rhs = m.right().node();
3913 :
3914 4814 : if (m.right().Is(-1) || m.right().Is(0)) {
3915 : return zero;
3916 2403 : } else if (m.right().HasValue()) {
3917 4784 : return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
3918 : }
3919 :
3920 : // General case for signed integer modulus, with optimization for (unknown)
3921 : // power of 2 right hand side.
3922 : //
3923 : // if 0 < rhs then
3924 : // msk = rhs - 1
3925 : // if rhs & msk != 0 then
3926 : // lhs % rhs
3927 : // else
3928 : // if lhs < 0 then
3929 : // -(-lhs & msk)
3930 : // else
3931 : // lhs & msk
3932 : // else
3933 : // if rhs < -1 then
3934 : // lhs % rhs
3935 : // else
3936 : // zero
3937 : //
3938 : // Note: We do not use the Diamond helper class here, because it really hurts
3939 : // readability with nested diamonds.
3940 11 : const Operator* const merge_op = common()->Merge(2);
3941 : const Operator* const phi_op =
3942 11 : common()->Phi(MachineRepresentation::kWord32, 2);
3943 :
3944 11 : Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3945 11 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3946 : graph()->start());
3947 :
3948 11 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3949 : Node* true0;
3950 : {
3951 11 : Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3952 :
3953 11 : Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3954 11 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
3955 :
3956 11 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3957 11 : Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3958 :
3959 11 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3960 : Node* false1;
3961 : {
3962 11 : Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
3963 11 : Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
3964 : check2, if_false1);
3965 :
3966 11 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3967 33 : Node* true2 = graph()->NewNode(
3968 : machine()->Int32Sub(), zero,
3969 : graph()->NewNode(machine()->Word32And(),
3970 : graph()->NewNode(machine()->Int32Sub(), zero, lhs),
3971 : msk));
3972 :
3973 11 : Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3974 11 : Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
3975 :
3976 : if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3977 : false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3978 : }
3979 :
3980 : if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
3981 : true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
3982 : }
3983 :
3984 11 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3985 : Node* false0;
3986 : {
3987 11 : Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3988 11 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
3989 : check1, if_false0);
3990 :
3991 11 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3992 11 : Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3993 :
3994 11 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3995 : Node* false1 = zero;
3996 :
3997 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3998 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3999 : }
4000 :
4001 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4002 11 : return graph()->NewNode(phi_op, true0, false0, merge0);
4003 : }
4004 :
4005 7 : Node* SimplifiedLowering::Int32Sign(Node* const node) {
4006 7 : Node* const minus_one = jsgraph()->Int32Constant(-1);
4007 7 : Node* const zero = jsgraph()->Int32Constant(0);
4008 7 : Node* const one = jsgraph()->Int32Constant(1);
4009 :
4010 : Node* const input = node->InputAt(0);
4011 :
4012 28 : return graph()->NewNode(
4013 : common()->Select(MachineRepresentation::kWord32),
4014 : graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
4015 : graph()->NewNode(
4016 : common()->Select(MachineRepresentation::kWord32),
4017 : graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
4018 7 : zero));
4019 : }
4020 :
4021 236 : Node* SimplifiedLowering::Uint32Div(Node* const node) {
4022 236 : Uint32BinopMatcher m(node);
4023 236 : Node* const zero = jsgraph()->Uint32Constant(0);
4024 : Node* const lhs = m.left().node();
4025 : Node* const rhs = m.right().node();
4026 :
4027 236 : if (m.right().Is(0)) {
4028 : return zero;
4029 229 : } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
4030 390 : return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
4031 : }
4032 :
4033 34 : Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4034 34 : Diamond d(graph(), common(), check, BranchHint::kFalse);
4035 34 : Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
4036 34 : return d.Phi(MachineRepresentation::kWord32, zero, div);
4037 : }
4038 :
4039 216 : Node* SimplifiedLowering::Uint32Mod(Node* const node) {
4040 216 : Uint32BinopMatcher m(node);
4041 216 : Node* const minus_one = jsgraph()->Int32Constant(-1);
4042 216 : Node* const zero = jsgraph()->Uint32Constant(0);
4043 : Node* const lhs = m.left().node();
4044 : Node* const rhs = m.right().node();
4045 :
4046 216 : if (m.right().Is(0)) {
4047 : return zero;
4048 216 : } else if (m.right().HasValue()) {
4049 386 : return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
4050 : }
4051 :
4052 : // General case for unsigned integer modulus, with optimization for (unknown)
4053 : // power of 2 right hand side.
4054 : //
4055 : // if rhs == 0 then
4056 : // zero
4057 : // else
4058 : // msk = rhs - 1
4059 : // if rhs & msk != 0 then
4060 : // lhs % rhs
4061 : // else
4062 : // lhs & msk
4063 : //
4064 : // Note: We do not use the Diamond helper class here, because it really hurts
4065 : // readability with nested diamonds.
4066 23 : const Operator* const merge_op = common()->Merge(2);
4067 : const Operator* const phi_op =
4068 23 : common()->Phi(MachineRepresentation::kWord32, 2);
4069 :
4070 23 : Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4071 23 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
4072 : graph()->start());
4073 :
4074 23 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4075 : Node* true0 = zero;
4076 :
4077 23 : Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4078 : Node* false0;
4079 : {
4080 23 : Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
4081 :
4082 23 : Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
4083 23 : Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4084 :
4085 23 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4086 23 : Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
4087 :
4088 23 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4089 23 : Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
4090 :
4091 : if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4092 : false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4093 : }
4094 :
4095 : Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4096 23 : return graph()->NewNode(phi_op, true0, false0, merge0);
4097 : }
4098 :
4099 2360 : void SimplifiedLowering::DoMax(Node* node, Operator const* op,
4100 : MachineRepresentation rep) {
4101 : Node* const lhs = node->InputAt(0);
4102 : Node* const rhs = node->InputAt(1);
4103 :
4104 2360 : node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
4105 : DCHECK_EQ(rhs, node->InputAt(1));
4106 2360 : node->AppendInput(graph()->zone(), lhs);
4107 2360 : NodeProperties::ChangeOp(node, common()->Select(rep));
4108 2360 : }
4109 :
4110 3139 : void SimplifiedLowering::DoMin(Node* node, Operator const* op,
4111 : MachineRepresentation rep) {
4112 : Node* const lhs = node->InputAt(0);
4113 : Node* const rhs = node->InputAt(1);
4114 :
4115 3139 : node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
4116 : DCHECK_EQ(lhs, node->InputAt(1));
4117 : DCHECK_EQ(rhs, node->InputAt(2));
4118 3139 : NodeProperties::ChangeOp(node, common()->Select(rep));
4119 3139 : }
4120 :
4121 151 : void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
4122 : Node* const input = node->InputAt(0);
4123 151 : Node* const zero = jsgraph()->Int32Constant(0);
4124 151 : Operator const* const op = machine()->Word32Equal();
4125 :
4126 151 : node->ReplaceInput(0, graph()->NewNode(op, input, zero));
4127 151 : node->AppendInput(graph()->zone(), zero);
4128 151 : NodeProperties::ChangeOp(node, op);
4129 151 : }
4130 :
4131 0 : void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
4132 : Node* const input = node->InputAt(0);
4133 :
4134 0 : node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
4135 0 : jsgraph()->Float64Constant(0.0)));
4136 0 : node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
4137 0 : NodeProperties::ChangeOp(node, machine()->Word32Equal());
4138 0 : }
4139 :
4140 32 : void SimplifiedLowering::DoNumberToBit(Node* node) {
4141 : Node* const input = node->InputAt(0);
4142 :
4143 32 : node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
4144 32 : node->AppendInput(graph()->zone(),
4145 32 : graph()->NewNode(machine()->Float64Abs(), input));
4146 32 : NodeProperties::ChangeOp(node, machine()->Float64LessThan());
4147 32 : }
4148 :
4149 21 : void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
4150 : Node* const input = node->InputAt(0);
4151 21 : Node* const min = jsgraph()->Float64Constant(0.0);
4152 21 : Node* const max = jsgraph()->Float64Constant(255.0);
4153 :
4154 21 : node->ReplaceInput(
4155 21 : 0, graph()->NewNode(machine()->Float64LessThan(), min, input));
4156 42 : node->AppendInput(
4157 : graph()->zone(),
4158 : graph()->NewNode(
4159 : common()->Select(MachineRepresentation::kFloat64),
4160 : graph()->NewNode(machine()->Float64LessThan(), input, max), input,
4161 21 : max));
4162 21 : node->AppendInput(graph()->zone(), min);
4163 21 : NodeProperties::ChangeOp(node,
4164 21 : common()->Select(MachineRepresentation::kFloat64));
4165 21 : }
4166 :
4167 294 : void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
4168 : Node* const input = node->InputAt(0);
4169 294 : Node* const min = jsgraph()->Float64Constant(0.0);
4170 294 : Node* const max = jsgraph()->Float64Constant(255.0);
4171 :
4172 1176 : node->ReplaceInput(
4173 : 0, graph()->NewNode(
4174 : common()->Select(MachineRepresentation::kFloat64),
4175 : graph()->NewNode(machine()->Float64LessThan(), min, input),
4176 : graph()->NewNode(
4177 : common()->Select(MachineRepresentation::kFloat64),
4178 : graph()->NewNode(machine()->Float64LessThan(), input, max),
4179 : input, max),
4180 294 : min));
4181 : NodeProperties::ChangeOp(node,
4182 294 : machine()->Float64RoundTiesEven().placeholder());
4183 294 : }
4184 :
4185 64 : void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
4186 : Node* const input = node->InputAt(0);
4187 64 : Node* const min = jsgraph()->Int32Constant(0);
4188 64 : Node* const max = jsgraph()->Int32Constant(255);
4189 :
4190 64 : node->ReplaceInput(
4191 64 : 0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
4192 128 : node->AppendInput(
4193 : graph()->zone(),
4194 : graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
4195 : graph()->NewNode(machine()->Int32LessThan(), input, min),
4196 64 : min, input));
4197 64 : node->AppendInput(graph()->zone(), max);
4198 64 : NodeProperties::ChangeOp(node,
4199 64 : common()->Select(MachineRepresentation::kWord32));
4200 64 : }
4201 :
4202 72 : void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
4203 : Node* const input = node->InputAt(0);
4204 72 : Node* const max = jsgraph()->Uint32Constant(255u);
4205 :
4206 72 : node->ReplaceInput(
4207 72 : 0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
4208 72 : node->AppendInput(graph()->zone(), input);
4209 72 : node->AppendInput(graph()->zone(), max);
4210 72 : NodeProperties::ChangeOp(node,
4211 72 : common()->Select(MachineRepresentation::kWord32));
4212 72 : }
4213 :
4214 1424 : Node* SimplifiedLowering::ToNumberCode() {
4215 1424 : if (!to_number_code_.is_set()) {
4216 1424 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
4217 2848 : to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
4218 : }
4219 1424 : return to_number_code_.get();
4220 : }
4221 :
4222 64 : Node* SimplifiedLowering::ToNumberConvertBigIntCode() {
4223 64 : if (!to_number_convert_big_int_code_.is_set()) {
4224 : Callable callable =
4225 64 : Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
4226 128 : to_number_convert_big_int_code_.set(
4227 : jsgraph()->HeapConstant(callable.code()));
4228 : }
4229 64 : return to_number_convert_big_int_code_.get();
4230 : }
4231 :
4232 0 : Node* SimplifiedLowering::ToNumericCode() {
4233 0 : if (!to_numeric_code_.is_set()) {
4234 0 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
4235 0 : to_numeric_code_.set(jsgraph()->HeapConstant(callable.code()));
4236 : }
4237 0 : return to_numeric_code_.get();
4238 : }
4239 :
4240 1424 : Operator const* SimplifiedLowering::ToNumberOperator() {
4241 1424 : if (!to_number_operator_.is_set()) {
4242 1424 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
4243 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4244 1424 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4245 1424 : graph()->zone(), callable.descriptor(),
4246 : callable.descriptor().GetStackParameterCount(), flags,
4247 1424 : Operator::kNoProperties);
4248 1424 : to_number_operator_.set(common()->Call(call_descriptor));
4249 : }
4250 1424 : return to_number_operator_.get();
4251 : }
4252 :
4253 0 : Operator const* SimplifiedLowering::ToNumberConvertBigIntOperator() {
4254 0 : if (!to_number_convert_big_int_operator_.is_set()) {
4255 : Callable callable =
4256 0 : Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
4257 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4258 0 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4259 0 : graph()->zone(), callable.descriptor(),
4260 : callable.descriptor().GetStackParameterCount(), flags,
4261 0 : Operator::kNoProperties);
4262 0 : to_number_convert_big_int_operator_.set(common()->Call(call_descriptor));
4263 : }
4264 0 : return to_number_convert_big_int_operator_.get();
4265 : }
4266 :
4267 64 : Operator const* SimplifiedLowering::ToNumericOperator() {
4268 64 : if (!to_numeric_operator_.is_set()) {
4269 64 : Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
4270 : CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4271 64 : auto call_descriptor = Linkage::GetStubCallDescriptor(
4272 64 : graph()->zone(), callable.descriptor(),
4273 : callable.descriptor().GetStackParameterCount(), flags,
4274 64 : Operator::kNoProperties);
4275 64 : to_numeric_operator_.set(common()->Call(call_descriptor));
4276 : }
4277 64 : return to_numeric_operator_.get();
4278 : }
4279 :
4280 : #undef TRACE
4281 :
4282 : } // namespace compiler
4283 : } // namespace internal
4284 122004 : } // namespace v8
|