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-properties.h"
19 #include "src/compiler/operation-typer.h"
20 #include "src/compiler/operator-properties.h"
21 #include "src/compiler/representation-change.h"
22 #include "src/compiler/simplified-operator.h"
23 #include "src/compiler/type-cache.h"
24 #include "src/conversions-inl.h"
25 #include "src/objects.h"
26
27 namespace v8 {
28 namespace internal {
29 namespace compiler {
30
31 // Macro for outputting trace information from representation inference.
32 #define TRACE(...) \
33 do { \
34 if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
35 } while (false)
36
37 // Representation selection and lowering of {Simplified} operators to machine
38 // operators are interwined. We use a fixpoint calculation to compute both the
39 // output representation and the best possible lowering for {Simplified} nodes.
40 // Representation change insertion ensures that all values are in the correct
41 // machine representation after this phase, as dictated by the machine
42 // operators themselves.
43 enum Phase {
44 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
45 // backwards from uses to definitions, around cycles in phis, according
46 // to local rules for each operator.
47 // During this phase, the usage information for a node determines the best
48 // possible lowering for each operator so far, and that in turn determines
49 // the output representation.
50 // Therefore, to be correct, this phase must iterate to a fixpoint before
51 // the next phase can begin.
52 PROPAGATE,
53
54 // 2.) RETYPE: Propagate types from type feedback forwards.
55 RETYPE,
56
57 // 3.) LOWER: perform lowering for all {Simplified} nodes by replacing some
58 // operators for some nodes, expanding some nodes to multiple nodes, or
59 // removing some (redundant) nodes.
60 // During this phase, use the {RepresentationChanger} to insert
61 // representation changes between uses that demand a particular
62 // representation and nodes that produce a different representation.
63 LOWER
64 };
65
66 namespace {
67
MachineRepresentationFromArrayType(ExternalArrayType array_type)68 MachineRepresentation MachineRepresentationFromArrayType(
69 ExternalArrayType array_type) {
70 switch (array_type) {
71 case kExternalUint8Array:
72 case kExternalUint8ClampedArray:
73 case kExternalInt8Array:
74 return MachineRepresentation::kWord8;
75 case kExternalUint16Array:
76 case kExternalInt16Array:
77 return MachineRepresentation::kWord16;
78 case kExternalUint32Array:
79 case kExternalInt32Array:
80 return MachineRepresentation::kWord32;
81 case kExternalFloat32Array:
82 return MachineRepresentation::kFloat32;
83 case kExternalFloat64Array:
84 return MachineRepresentation::kFloat64;
85 }
86 UNREACHABLE();
87 return MachineRepresentation::kNone;
88 }
89
CheckedUseInfoAsWord32FromHint(NumberOperationHint hint,CheckForMinusZeroMode minus_zero_mode=CheckForMinusZeroMode::kCheckForMinusZero)90 UseInfo CheckedUseInfoAsWord32FromHint(
91 NumberOperationHint hint, CheckForMinusZeroMode minus_zero_mode =
92 CheckForMinusZeroMode::kCheckForMinusZero) {
93 switch (hint) {
94 case NumberOperationHint::kSignedSmall:
95 return UseInfo::CheckedSignedSmallAsWord32(minus_zero_mode);
96 case NumberOperationHint::kSigned32:
97 return UseInfo::CheckedSigned32AsWord32(minus_zero_mode);
98 case NumberOperationHint::kNumber:
99 return UseInfo::CheckedNumberAsWord32();
100 case NumberOperationHint::kNumberOrOddball:
101 return UseInfo::CheckedNumberOrOddballAsWord32();
102 }
103 UNREACHABLE();
104 return UseInfo::None();
105 }
106
CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint)107 UseInfo CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint) {
108 switch (hint) {
109 case NumberOperationHint::kSignedSmall:
110 case NumberOperationHint::kSigned32:
111 // Not used currently.
112 UNREACHABLE();
113 break;
114 case NumberOperationHint::kNumber:
115 return UseInfo::CheckedNumberAsFloat64();
116 case NumberOperationHint::kNumberOrOddball:
117 return UseInfo::CheckedNumberOrOddballAsFloat64();
118 }
119 UNREACHABLE();
120 return UseInfo::None();
121 }
122
TruncatingUseInfoFromRepresentation(MachineRepresentation rep)123 UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
124 switch (rep) {
125 case MachineRepresentation::kTaggedSigned:
126 case MachineRepresentation::kTaggedPointer:
127 case MachineRepresentation::kTagged:
128 return UseInfo::AnyTagged();
129 case MachineRepresentation::kFloat64:
130 return UseInfo::TruncatingFloat64();
131 case MachineRepresentation::kFloat32:
132 return UseInfo::Float32();
133 case MachineRepresentation::kWord64:
134 return UseInfo::TruncatingWord64();
135 case MachineRepresentation::kWord8:
136 case MachineRepresentation::kWord16:
137 case MachineRepresentation::kWord32:
138 return UseInfo::TruncatingWord32();
139 case MachineRepresentation::kBit:
140 return UseInfo::Bool();
141 case MachineRepresentation::kSimd128: // Fall through.
142 case MachineRepresentation::kNone:
143 break;
144 }
145 UNREACHABLE();
146 return UseInfo::None();
147 }
148
149
UseInfoForBasePointer(const FieldAccess & access)150 UseInfo UseInfoForBasePointer(const FieldAccess& access) {
151 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
152 }
153
154
UseInfoForBasePointer(const ElementAccess & access)155 UseInfo UseInfoForBasePointer(const ElementAccess& access) {
156 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt();
157 }
158
ReplaceEffectControlUses(Node * node,Node * effect,Node * control)159 void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
160 for (Edge edge : node->use_edges()) {
161 if (NodeProperties::IsControlEdge(edge)) {
162 edge.UpdateTo(control);
163 } else if (NodeProperties::IsEffectEdge(edge)) {
164 edge.UpdateTo(effect);
165 } else {
166 DCHECK(NodeProperties::IsValueEdge(edge) ||
167 NodeProperties::IsContextEdge(edge));
168 }
169 }
170 }
171
ChangeToPureOp(Node * node,const Operator * new_op)172 void ChangeToPureOp(Node* node, const Operator* new_op) {
173 if (node->op()->EffectInputCount() > 0) {
174 DCHECK_LT(0, node->op()->ControlInputCount());
175 // Disconnect the node from effect and control chains.
176 Node* control = NodeProperties::GetControlInput(node);
177 Node* effect = NodeProperties::GetEffectInput(node);
178 ReplaceEffectControlUses(node, effect, control);
179 node->TrimInputCount(new_op->ValueInputCount());
180 } else {
181 DCHECK_EQ(0, node->op()->ControlInputCount());
182 }
183 NodeProperties::ChangeOp(node, new_op);
184 }
185
186 #ifdef DEBUG
187 // Helpers for monotonicity checking.
188 class InputUseInfos {
189 public:
InputUseInfos(Zone * zone)190 explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
191
SetAndCheckInput(Node * node,int index,UseInfo use_info)192 void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
193 if (input_use_infos_.empty()) {
194 input_use_infos_.resize(node->InputCount(), UseInfo::None());
195 }
196 // Check that the new use informatin is a super-type of the old
197 // one.
198 CHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
199 input_use_infos_[index] = use_info;
200 }
201
202 private:
203 ZoneVector<UseInfo> input_use_infos_;
204
IsUseLessGeneral(UseInfo use1,UseInfo use2)205 static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
206 return use1.truncation().IsLessGeneralThan(use2.truncation());
207 }
208 };
209
210 #endif // DEBUG
211
212 } // namespace
213
214
215 class RepresentationSelector {
216 public:
217 // Information for each node tracked during the fixpoint.
218 class NodeInfo final {
219 public:
220 // Adds new use to the node. Returns true if something has changed
221 // and the node has to be requeued.
AddUse(UseInfo info)222 bool AddUse(UseInfo info) {
223 Truncation old_truncation = truncation_;
224 truncation_ = Truncation::Generalize(truncation_, info.truncation());
225 return truncation_ != old_truncation;
226 }
227
set_queued()228 void set_queued() { state_ = kQueued; }
set_visited()229 void set_visited() { state_ = kVisited; }
set_pushed()230 void set_pushed() { state_ = kPushed; }
reset_state()231 void reset_state() { state_ = kUnvisited; }
visited() const232 bool visited() const { return state_ == kVisited; }
queued() const233 bool queued() const { return state_ == kQueued; }
unvisited() const234 bool unvisited() const { return state_ == kUnvisited; }
truncation() const235 Truncation truncation() const { return truncation_; }
set_output(MachineRepresentation output)236 void set_output(MachineRepresentation output) { representation_ = output; }
237
representation() const238 MachineRepresentation representation() const { return representation_; }
239
240 // Helpers for feedback typing.
set_feedback_type(Type * type)241 void set_feedback_type(Type* type) { feedback_type_ = type; }
feedback_type() const242 Type* feedback_type() const { return feedback_type_; }
set_weakened()243 void set_weakened() { weakened_ = true; }
weakened() const244 bool weakened() const { return weakened_; }
set_restriction_type(Type * type)245 void set_restriction_type(Type* type) { restriction_type_ = type; }
restriction_type() const246 Type* restriction_type() const { return restriction_type_; }
247
248 private:
249 enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
250 State state_ = kUnvisited;
251 MachineRepresentation representation_ =
252 MachineRepresentation::kNone; // Output representation.
253 Truncation truncation_ = Truncation::None(); // Information about uses.
254
255 Type* restriction_type_ = Type::Any();
256 Type* feedback_type_ = nullptr;
257 bool weakened_ = false;
258 };
259
RepresentationSelector(JSGraph * jsgraph,Zone * zone,RepresentationChanger * changer,SourcePositionTable * source_positions)260 RepresentationSelector(JSGraph* jsgraph, Zone* zone,
261 RepresentationChanger* changer,
262 SourcePositionTable* source_positions)
263 : jsgraph_(jsgraph),
264 zone_(zone),
265 count_(jsgraph->graph()->NodeCount()),
266 info_(count_, zone),
267 #ifdef DEBUG
268 node_input_use_infos_(count_, InputUseInfos(zone), zone),
269 #endif
270 nodes_(zone),
271 replacements_(zone),
272 phase_(PROPAGATE),
273 changer_(changer),
274 queue_(zone),
275 typing_stack_(zone),
276 source_positions_(source_positions),
277 type_cache_(TypeCache::Get()),
278 op_typer_(jsgraph->isolate(), graph_zone()) {
279 }
280
281 // Forward propagation of types from type feedback.
RunTypePropagationPhase()282 void RunTypePropagationPhase() {
283 // Run type propagation.
284 TRACE("--{Type propagation phase}--\n");
285 phase_ = RETYPE;
286 ResetNodeInfoState();
287
288 DCHECK(typing_stack_.empty());
289 typing_stack_.push({graph()->end(), 0});
290 GetInfo(graph()->end())->set_pushed();
291 while (!typing_stack_.empty()) {
292 NodeState& current = typing_stack_.top();
293
294 // If there is an unvisited input, push it and continue.
295 bool pushed_unvisited = false;
296 while (current.input_index < current.node->InputCount()) {
297 Node* input = current.node->InputAt(current.input_index);
298 NodeInfo* input_info = GetInfo(input);
299 current.input_index++;
300 if (input_info->unvisited()) {
301 input_info->set_pushed();
302 typing_stack_.push({input, 0});
303 pushed_unvisited = true;
304 break;
305 }
306 }
307 if (pushed_unvisited) continue;
308
309 // Process the top of the stack.
310 Node* node = current.node;
311 typing_stack_.pop();
312 NodeInfo* info = GetInfo(node);
313 info->set_visited();
314 bool updated = UpdateFeedbackType(node);
315 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
316 VisitNode(node, info->truncation(), nullptr);
317 TRACE(" ==> output ");
318 PrintOutputInfo(info);
319 TRACE("\n");
320 if (updated) {
321 for (Node* const user : node->uses()) {
322 if (GetInfo(user)->visited()) {
323 GetInfo(user)->set_queued();
324 queue_.push(user);
325 }
326 }
327 }
328 }
329
330 // Process the revisit queue.
331 while (!queue_.empty()) {
332 Node* node = queue_.front();
333 queue_.pop();
334 NodeInfo* info = GetInfo(node);
335 info->set_visited();
336 bool updated = UpdateFeedbackType(node);
337 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
338 VisitNode(node, info->truncation(), nullptr);
339 TRACE(" ==> output ");
340 PrintOutputInfo(info);
341 TRACE("\n");
342 if (updated) {
343 for (Node* const user : node->uses()) {
344 if (GetInfo(user)->visited()) {
345 GetInfo(user)->set_queued();
346 queue_.push(user);
347 }
348 }
349 }
350 }
351 }
352
ResetNodeInfoState()353 void ResetNodeInfoState() {
354 // Clean up for the next phase.
355 for (NodeInfo& info : info_) {
356 info.reset_state();
357 }
358 }
359
TypeOf(Node * node)360 Type* TypeOf(Node* node) {
361 Type* type = GetInfo(node)->feedback_type();
362 return type == nullptr ? NodeProperties::GetType(node) : type;
363 }
364
FeedbackTypeOf(Node * node)365 Type* FeedbackTypeOf(Node* node) {
366 Type* type = GetInfo(node)->feedback_type();
367 return type == nullptr ? Type::None() : type;
368 }
369
TypePhi(Node * node)370 Type* TypePhi(Node* node) {
371 int arity = node->op()->ValueInputCount();
372 Type* type = FeedbackTypeOf(node->InputAt(0));
373 for (int i = 1; i < arity; ++i) {
374 type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
375 }
376 return type;
377 }
378
TypeSelect(Node * node)379 Type* TypeSelect(Node* node) {
380 return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
381 FeedbackTypeOf(node->InputAt(2)));
382 }
383
UpdateFeedbackType(Node * node)384 bool UpdateFeedbackType(Node* node) {
385 if (node->op()->ValueOutputCount() == 0) return false;
386
387 NodeInfo* info = GetInfo(node);
388 Type* type = info->feedback_type();
389 Type* new_type = type;
390
391 // For any non-phi node just wait until we get all inputs typed. We only
392 // allow untyped inputs for phi nodes because phis are the only places
393 // where cycles need to be broken.
394 if (node->opcode() != IrOpcode::kPhi) {
395 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
396 if (GetInfo(node->InputAt(i))->feedback_type() == nullptr) {
397 return false;
398 }
399 }
400 }
401
402 switch (node->opcode()) {
403 #define DECLARE_CASE(Name) \
404 case IrOpcode::k##Name: { \
405 new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
406 FeedbackTypeOf(node->InputAt(1))); \
407 break; \
408 }
409 SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
410 #undef DECLARE_CASE
411
412 #define DECLARE_CASE(Name) \
413 case IrOpcode::k##Name: { \
414 new_type = \
415 Type::Intersect(op_typer_.Name(FeedbackTypeOf(node->InputAt(0)), \
416 FeedbackTypeOf(node->InputAt(1))), \
417 info->restriction_type(), graph_zone()); \
418 break; \
419 }
420 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
421 #undef DECLARE_CASE
422
423 #define DECLARE_CASE(Name) \
424 case IrOpcode::k##Name: { \
425 new_type = op_typer_.Name(FeedbackTypeOf(node->InputAt(0))); \
426 break; \
427 }
428 SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
429 #undef DECLARE_CASE
430
431 case IrOpcode::kPlainPrimitiveToNumber:
432 new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
433 break;
434
435 case IrOpcode::kPhi: {
436 new_type = TypePhi(node);
437 if (type != nullptr) {
438 new_type = Weaken(node, type, new_type);
439 }
440 break;
441 }
442
443 case IrOpcode::kTypeGuard: {
444 new_type = op_typer_.TypeTypeGuard(node->op(),
445 FeedbackTypeOf(node->InputAt(0)));
446 break;
447 }
448
449 case IrOpcode::kSelect: {
450 new_type = TypeSelect(node);
451 break;
452 }
453
454 default:
455 // Shortcut for operations that we do not handle.
456 if (type == nullptr) {
457 GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
458 return true;
459 }
460 return false;
461 }
462 // We need to guarantee that the feedback type is a subtype of the upper
463 // bound. Naively that should hold, but weakening can actually produce
464 // a bigger type if we are unlucky with ordering of phi typing. To be
465 // really sure, just intersect the upper bound with the feedback type.
466 new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());
467
468 if (type != nullptr && new_type->Is(type)) return false;
469 GetInfo(node)->set_feedback_type(new_type);
470 if (FLAG_trace_representation) {
471 PrintNodeFeedbackType(node);
472 }
473 return true;
474 }
475
PrintNodeFeedbackType(Node * n)476 void PrintNodeFeedbackType(Node* n) {
477 OFStream os(stdout);
478 os << "#" << n->id() << ":" << *n->op() << "(";
479 int j = 0;
480 for (Node* const i : n->inputs()) {
481 if (j++ > 0) os << ", ";
482 os << "#" << i->id() << ":" << i->op()->mnemonic();
483 }
484 os << ")";
485 if (NodeProperties::IsTyped(n)) {
486 os << " [Static type: ";
487 Type* static_type = NodeProperties::GetType(n);
488 static_type->PrintTo(os);
489 Type* feedback_type = GetInfo(n)->feedback_type();
490 if (feedback_type != nullptr && feedback_type != static_type) {
491 os << ", Feedback type: ";
492 feedback_type->PrintTo(os);
493 }
494 os << "]";
495 }
496 os << std::endl;
497 }
498
Weaken(Node * node,Type * previous_type,Type * current_type)499 Type* Weaken(Node* node, Type* previous_type, Type* current_type) {
500 // If the types have nothing to do with integers, return the types.
501 Type* const integer = type_cache_.kInteger;
502 if (!previous_type->Maybe(integer)) {
503 return current_type;
504 }
505 DCHECK(current_type->Maybe(integer));
506
507 Type* current_integer =
508 Type::Intersect(current_type, integer, graph_zone());
509 Type* previous_integer =
510 Type::Intersect(previous_type, integer, graph_zone());
511
512 // Once we start weakening a node, we should always weaken.
513 if (!GetInfo(node)->weakened()) {
514 // Only weaken if there is range involved; we should converge quickly
515 // for all other types (the exception is a union of many constants,
516 // but we currently do not increase the number of constants in unions).
517 Type* previous = previous_integer->GetRange();
518 Type* current = current_integer->GetRange();
519 if (current == nullptr || previous == nullptr) {
520 return current_type;
521 }
522 // Range is involved => we are weakening.
523 GetInfo(node)->set_weakened();
524 }
525
526 return Type::Union(current_type,
527 op_typer_.WeakenRange(previous_integer, current_integer),
528 graph_zone());
529 }
530
531 // Backward propagation of truncations.
RunTruncationPropagationPhase()532 void RunTruncationPropagationPhase() {
533 // Run propagation phase to a fixpoint.
534 TRACE("--{Propagation phase}--\n");
535 phase_ = PROPAGATE;
536 EnqueueInitial(jsgraph_->graph()->end());
537 // Process nodes from the queue until it is empty.
538 while (!queue_.empty()) {
539 Node* node = queue_.front();
540 NodeInfo* info = GetInfo(node);
541 queue_.pop();
542 info->set_visited();
543 TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
544 info->truncation().description());
545 VisitNode(node, info->truncation(), nullptr);
546 }
547 }
548
Run(SimplifiedLowering * lowering)549 void Run(SimplifiedLowering* lowering) {
550 RunTruncationPropagationPhase();
551
552 RunTypePropagationPhase();
553
554 // Run lowering and change insertion phase.
555 TRACE("--{Simplified lowering phase}--\n");
556 phase_ = LOWER;
557 // Process nodes from the collected {nodes_} vector.
558 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
559 Node* node = *i;
560 NodeInfo* info = GetInfo(node);
561 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
562 // Reuse {VisitNode()} so the representation rules are in one place.
563 SourcePositionTable::Scope scope(
564 source_positions_, source_positions_->GetSourcePosition(node));
565 VisitNode(node, info->truncation(), lowering);
566 }
567
568 // Perform the final replacements.
569 for (NodeVector::iterator i = replacements_.begin();
570 i != replacements_.end(); ++i) {
571 Node* node = *i;
572 Node* replacement = *(++i);
573 node->ReplaceUses(replacement);
574 node->Kill();
575 // We also need to replace the node in the rest of the vector.
576 for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
577 ++j;
578 if (*j == node) *j = replacement;
579 }
580 }
581 }
582
EnqueueInitial(Node * node)583 void EnqueueInitial(Node* node) {
584 NodeInfo* info = GetInfo(node);
585 info->set_queued();
586 nodes_.push_back(node);
587 queue_.push(node);
588 }
589
590 // Enqueue {use_node}'s {index} input if the {use} contains new information
591 // for that input node. Add the input to {nodes_} if this is the first time
592 // it's been visited.
EnqueueInput(Node * use_node,int index,UseInfo use_info=UseInfo::None ())593 void EnqueueInput(Node* use_node, int index,
594 UseInfo use_info = UseInfo::None()) {
595 Node* node = use_node->InputAt(index);
596 if (phase_ != PROPAGATE) return;
597 NodeInfo* info = GetInfo(node);
598 #ifdef DEBUG
599 // Check monotonicity of input requirements.
600 node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
601 use_info);
602 #endif // DEBUG
603 if (info->unvisited()) {
604 // First visit of this node.
605 info->set_queued();
606 nodes_.push_back(node);
607 queue_.push(node);
608 TRACE(" initial #%i: ", node->id());
609 info->AddUse(use_info);
610 PrintTruncation(info->truncation());
611 return;
612 }
613 TRACE(" queue #%i?: ", node->id());
614 PrintTruncation(info->truncation());
615 if (info->AddUse(use_info)) {
616 // New usage information for the node is available.
617 if (!info->queued()) {
618 queue_.push(node);
619 info->set_queued();
620 TRACE(" added: ");
621 } else {
622 TRACE(" inqueue: ");
623 }
624 PrintTruncation(info->truncation());
625 }
626 }
627
lower() const628 bool lower() const { return phase_ == LOWER; }
retype() const629 bool retype() const { return phase_ == RETYPE; }
propagate() const630 bool propagate() const { return phase_ == PROPAGATE; }
631
SetOutput(Node * node,MachineRepresentation representation,Type * restriction_type=Type::Any ())632 void SetOutput(Node* node, MachineRepresentation representation,
633 Type* restriction_type = Type::Any()) {
634 NodeInfo* const info = GetInfo(node);
635 switch (phase_) {
636 case PROPAGATE:
637 info->set_restriction_type(restriction_type);
638 break;
639 case RETYPE:
640 DCHECK(info->restriction_type()->Is(restriction_type));
641 DCHECK(restriction_type->Is(info->restriction_type()));
642 info->set_output(representation);
643 break;
644 case LOWER:
645 DCHECK_EQ(info->representation(), representation);
646 DCHECK(info->restriction_type()->Is(restriction_type));
647 DCHECK(restriction_type->Is(info->restriction_type()));
648 break;
649 }
650 }
651
GetUpperBound(Node * node)652 Type* GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
653
InputCannotBe(Node * node,Type * type)654 bool InputCannotBe(Node* node, Type* type) {
655 DCHECK_EQ(1, node->op()->ValueInputCount());
656 return !GetUpperBound(node->InputAt(0))->Maybe(type);
657 }
658
InputIs(Node * node,Type * type)659 bool InputIs(Node* node, Type* type) {
660 DCHECK_EQ(1, node->op()->ValueInputCount());
661 return GetUpperBound(node->InputAt(0))->Is(type);
662 }
663
BothInputsAreSigned32(Node * node)664 bool BothInputsAreSigned32(Node* node) {
665 return BothInputsAre(node, Type::Signed32());
666 }
667
BothInputsAreUnsigned32(Node * node)668 bool BothInputsAreUnsigned32(Node* node) {
669 return BothInputsAre(node, Type::Unsigned32());
670 }
671
BothInputsAre(Node * node,Type * type)672 bool BothInputsAre(Node* node, Type* type) {
673 DCHECK_EQ(2, node->op()->ValueInputCount());
674 return GetUpperBound(node->InputAt(0))->Is(type) &&
675 GetUpperBound(node->InputAt(1))->Is(type);
676 }
677
OneInputCannotBe(Node * node,Type * type)678 bool OneInputCannotBe(Node* node, Type* type) {
679 DCHECK_EQ(2, node->op()->ValueInputCount());
680 return !GetUpperBound(node->InputAt(0))->Maybe(type) ||
681 !GetUpperBound(node->InputAt(1))->Maybe(type);
682 }
683
ConvertInput(Node * node,int index,UseInfo use)684 void ConvertInput(Node* node, int index, UseInfo use) {
685 Node* input = node->InputAt(index);
686 // In the change phase, insert a change before the use if necessary.
687 if (use.representation() == MachineRepresentation::kNone)
688 return; // No input requirement on the use.
689 DCHECK_NOT_NULL(input);
690 NodeInfo* input_info = GetInfo(input);
691 MachineRepresentation input_rep = input_info->representation();
692 if (input_rep != use.representation() ||
693 use.type_check() != TypeCheckKind::kNone) {
694 // Output representation doesn't match usage.
695 TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
696 index, input->id(), input->op()->mnemonic());
697 TRACE(" from ");
698 PrintOutputInfo(input_info);
699 TRACE(" to ");
700 PrintUseInfo(use);
701 TRACE("\n");
702 Node* n = changer_->GetRepresentationFor(
703 input, input_info->representation(), TypeOf(input), node, use);
704 node->ReplaceInput(index, n);
705 }
706 }
707
ProcessInput(Node * node,int index,UseInfo use)708 void ProcessInput(Node* node, int index, UseInfo use) {
709 switch (phase_) {
710 case PROPAGATE:
711 EnqueueInput(node, index, use);
712 break;
713 case RETYPE:
714 break;
715 case LOWER:
716 ConvertInput(node, index, use);
717 break;
718 }
719 }
720
ProcessRemainingInputs(Node * node,int index)721 void ProcessRemainingInputs(Node* node, int index) {
722 DCHECK_GE(index, NodeProperties::PastValueIndex(node));
723 DCHECK_GE(index, NodeProperties::PastContextIndex(node));
724 for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
725 i < NodeProperties::PastEffectIndex(node); ++i) {
726 EnqueueInput(node, i); // Effect inputs: just visit
727 }
728 for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
729 i < NodeProperties::PastControlIndex(node); ++i) {
730 EnqueueInput(node, i); // Control inputs: just visit
731 }
732 }
733
734 // The default, most general visitation case. For {node}, process all value,
735 // context, frame state, effect, and control inputs, assuming that value
736 // inputs should have {kRepTagged} representation and can observe all output
737 // values {kTypeAny}.
VisitInputs(Node * node)738 void VisitInputs(Node* node) {
739 int tagged_count = node->op()->ValueInputCount() +
740 OperatorProperties::GetContextInputCount(node->op()) +
741 OperatorProperties::GetFrameStateInputCount(node->op());
742 // Visit value, context and frame state inputs as tagged.
743 for (int i = 0; i < tagged_count; i++) {
744 ProcessInput(node, i, UseInfo::AnyTagged());
745 }
746 // Only enqueue other inputs (effects, control).
747 for (int i = tagged_count; i < node->InputCount(); i++) {
748 EnqueueInput(node, i);
749 }
750 }
751
VisitReturn(Node * node)752 void VisitReturn(Node* node) {
753 int tagged_limit = node->op()->ValueInputCount() +
754 OperatorProperties::GetContextInputCount(node->op()) +
755 OperatorProperties::GetFrameStateInputCount(node->op());
756 // Visit integer slot count to pop
757 ProcessInput(node, 0, UseInfo::TruncatingWord32());
758
759 // Visit value, context and frame state inputs as tagged.
760 for (int i = 1; i < tagged_limit; i++) {
761 ProcessInput(node, i, UseInfo::AnyTagged());
762 }
763 // Only enqueue other inputs (effects, control).
764 for (int i = tagged_limit; i < node->InputCount(); i++) {
765 EnqueueInput(node, i);
766 }
767 }
768
769 // Helper for an unused node.
VisitUnused(Node * node)770 void VisitUnused(Node* node) {
771 int value_count = node->op()->ValueInputCount() +
772 OperatorProperties::GetContextInputCount(node->op()) +
773 OperatorProperties::GetFrameStateInputCount(node->op());
774 for (int i = 0; i < value_count; i++) {
775 ProcessInput(node, i, UseInfo::None());
776 }
777 ProcessRemainingInputs(node, value_count);
778 if (lower()) Kill(node);
779 }
780
781 // Helper for binops of the R x L -> O variety.
VisitBinop(Node * node,UseInfo left_use,UseInfo right_use,MachineRepresentation output,Type * restriction_type=Type::Any ())782 void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
783 MachineRepresentation output,
784 Type* restriction_type = Type::Any()) {
785 DCHECK_EQ(2, node->op()->ValueInputCount());
786 ProcessInput(node, 0, left_use);
787 ProcessInput(node, 1, right_use);
788 for (int i = 2; i < node->InputCount(); i++) {
789 EnqueueInput(node, i);
790 }
791 SetOutput(node, output, restriction_type);
792 }
793
794 // Helper for binops of the I x I -> O variety.
VisitBinop(Node * node,UseInfo input_use,MachineRepresentation output,Type * restriction_type=Type::Any ())795 void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output,
796 Type* restriction_type = Type::Any()) {
797 VisitBinop(node, input_use, input_use, output, restriction_type);
798 }
799
VisitSpeculativeInt32Binop(Node * node)800 void VisitSpeculativeInt32Binop(Node* node) {
801 DCHECK_EQ(2, node->op()->ValueInputCount());
802 if (BothInputsAre(node, Type::NumberOrOddball())) {
803 return VisitBinop(node, UseInfo::TruncatingWord32(),
804 MachineRepresentation::kWord32);
805 }
806 NumberOperationHint hint = NumberOperationHintOf(node->op());
807 return VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
808 MachineRepresentation::kWord32);
809 }
810
811 // Helper for unops of the I -> O variety.
VisitUnop(Node * node,UseInfo input_use,MachineRepresentation output)812 void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output) {
813 DCHECK_EQ(1, node->op()->ValueInputCount());
814 ProcessInput(node, 0, input_use);
815 ProcessRemainingInputs(node, 1);
816 SetOutput(node, output);
817 }
818
819 // Helper for leaf nodes.
VisitLeaf(Node * node,MachineRepresentation output)820 void VisitLeaf(Node* node, MachineRepresentation output) {
821 DCHECK_EQ(0, node->InputCount());
822 SetOutput(node, output);
823 }
824
825 // Helpers for specific types of binops.
VisitFloat64Binop(Node * node)826 void VisitFloat64Binop(Node* node) {
827 VisitBinop(node, UseInfo::TruncatingFloat64(),
828 MachineRepresentation::kFloat64);
829 }
VisitWord32TruncatingBinop(Node * node)830 void VisitWord32TruncatingBinop(Node* node) {
831 VisitBinop(node, UseInfo::TruncatingWord32(),
832 MachineRepresentation::kWord32);
833 }
834
835 // Infer representation for phi-like nodes.
836 // The {node} parameter is only used to decide on the int64 representation.
837 // Once the type system supports an external pointer type, the {node}
838 // parameter can be removed.
GetOutputInfoForPhi(Node * node,Type * type,Truncation use)839 MachineRepresentation GetOutputInfoForPhi(Node* node, Type* type,
840 Truncation use) {
841 // Compute the representation.
842 if (type->Is(Type::None())) {
843 return MachineRepresentation::kNone;
844 } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) {
845 return MachineRepresentation::kWord32;
846 } else if (type->Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
847 return MachineRepresentation::kWord32;
848 } else if (type->Is(Type::Boolean())) {
849 return MachineRepresentation::kBit;
850 } else if (type->Is(Type::NumberOrOddball()) && use.IsUsedAsFloat64()) {
851 return MachineRepresentation::kFloat64;
852 } else if (type->Is(
853 Type::Union(Type::SignedSmall(), Type::NaN(), zone()))) {
854 // TODO(turbofan): For Phis that return either NaN or some Smi, it's
855 // beneficial to not go all the way to double, unless the uses are
856 // double uses. For tagging that just means some potentially expensive
857 // allocation code; we might want to do the same for -0 as well?
858 return MachineRepresentation::kTagged;
859 } else if (type->Is(Type::Number())) {
860 return MachineRepresentation::kFloat64;
861 } else if (type->Is(Type::ExternalPointer())) {
862 return MachineType::PointerRepresentation();
863 }
864 return MachineRepresentation::kTagged;
865 }
866
867 // Helper for handling selects.
VisitSelect(Node * node,Truncation truncation,SimplifiedLowering * lowering)868 void VisitSelect(Node* node, Truncation truncation,
869 SimplifiedLowering* lowering) {
870 ProcessInput(node, 0, UseInfo::Bool());
871
872 MachineRepresentation output =
873 GetOutputInfoForPhi(node, TypeOf(node), truncation);
874 SetOutput(node, output);
875
876 if (lower()) {
877 // Update the select operator.
878 SelectParameters p = SelectParametersOf(node->op());
879 if (output != p.representation()) {
880 NodeProperties::ChangeOp(node,
881 lowering->common()->Select(output, p.hint()));
882 }
883 }
884 // Convert inputs to the output representation of this phi, pass the
885 // truncation truncation along.
886 UseInfo input_use(output, truncation);
887 ProcessInput(node, 1, input_use);
888 ProcessInput(node, 2, input_use);
889 }
890
891 // Helper for handling phis.
VisitPhi(Node * node,Truncation truncation,SimplifiedLowering * lowering)892 void VisitPhi(Node* node, Truncation truncation,
893 SimplifiedLowering* lowering) {
894 MachineRepresentation output =
895 GetOutputInfoForPhi(node, TypeOf(node), truncation);
896 // Only set the output representation if not running with type
897 // feedback. (Feedback typing will set the representation.)
898 SetOutput(node, output);
899
900 int values = node->op()->ValueInputCount();
901 if (lower()) {
902 // Update the phi operator.
903 if (output != PhiRepresentationOf(node->op())) {
904 NodeProperties::ChangeOp(node, lowering->common()->Phi(output, values));
905 }
906 }
907
908 // Convert inputs to the output representation of this phi, pass the
909 // truncation along.
910 UseInfo input_use(output, truncation);
911 for (int i = 0; i < node->InputCount(); i++) {
912 ProcessInput(node, i, i < values ? input_use : UseInfo::None());
913 }
914 }
915
VisitObjectIs(Node * node,Type * type,SimplifiedLowering * lowering)916 void VisitObjectIs(Node* node, Type* type, SimplifiedLowering* lowering) {
917 Type* const input_type = TypeOf(node->InputAt(0));
918 if (input_type->Is(type)) {
919 VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit);
920 if (lower()) {
921 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
922 }
923 } else {
924 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
925 if (lower() && !input_type->Maybe(type)) {
926 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
927 }
928 }
929 }
930
VisitCall(Node * node,SimplifiedLowering * lowering)931 void VisitCall(Node* node, SimplifiedLowering* lowering) {
932 const CallDescriptor* desc = CallDescriptorOf(node->op());
933 int params = static_cast<int>(desc->ParameterCount());
934 int value_input_count = node->op()->ValueInputCount();
935 // Propagate representation information from call descriptor.
936 for (int i = 0; i < value_input_count; i++) {
937 if (i == 0) {
938 // The target of the call.
939 ProcessInput(node, i, UseInfo::Any());
940 } else if ((i - 1) < params) {
941 ProcessInput(node, i, TruncatingUseInfoFromRepresentation(
942 desc->GetInputType(i).representation()));
943 } else {
944 ProcessInput(node, i, UseInfo::AnyTagged());
945 }
946 }
947 ProcessRemainingInputs(node, value_input_count);
948
949 if (desc->ReturnCount() > 0) {
950 SetOutput(node, desc->GetReturnType(0).representation());
951 } else {
952 SetOutput(node, MachineRepresentation::kTagged);
953 }
954 }
955
DeoptValueSemanticOf(Type * type)956 MachineSemantic DeoptValueSemanticOf(Type* type) {
957 // We only need signedness to do deopt correctly.
958 if (type->Is(Type::Signed32())) {
959 return MachineSemantic::kInt32;
960 } else if (type->Is(Type::Unsigned32())) {
961 return MachineSemantic::kUint32;
962 } else {
963 return MachineSemantic::kAny;
964 }
965 }
966
VisitStateValues(Node * node)967 void VisitStateValues(Node* node) {
968 if (propagate()) {
969 for (int i = 0; i < node->InputCount(); i++) {
970 EnqueueInput(node, i, UseInfo::Any());
971 }
972 } else if (lower()) {
973 Zone* zone = jsgraph_->zone();
974 ZoneVector<MachineType>* types =
975 new (zone->New(sizeof(ZoneVector<MachineType>)))
976 ZoneVector<MachineType>(node->InputCount(), zone);
977 for (int i = 0; i < node->InputCount(); i++) {
978 Node* input = node->InputAt(i);
979 NodeInfo* input_info = GetInfo(input);
980 Type* input_type = TypeOf(input);
981 MachineRepresentation rep = input_type->IsInhabited()
982 ? input_info->representation()
983 : MachineRepresentation::kNone;
984 MachineType machine_type(rep, DeoptValueSemanticOf(input_type));
985 DCHECK(machine_type.representation() !=
986 MachineRepresentation::kWord32 ||
987 machine_type.semantic() == MachineSemantic::kInt32 ||
988 machine_type.semantic() == MachineSemantic::kUint32);
989 (*types)[i] = machine_type;
990 }
991 NodeProperties::ChangeOp(node,
992 jsgraph_->common()->TypedStateValues(types));
993 }
994 SetOutput(node, MachineRepresentation::kTagged);
995 }
996
VisitObjectState(Node * node)997 void VisitObjectState(Node* node) {
998 if (propagate()) {
999 for (int i = 0; i < node->InputCount(); i++) {
1000 Node* input = node->InputAt(i);
1001 Type* input_type = TypeOf(input);
1002 // TODO(turbofan): Special treatment for ExternalPointer here,
1003 // to avoid incompatible truncations. We really need a story
1004 // for the JSFunction::entry field.
1005 UseInfo use_info = input_type->Is(Type::ExternalPointer())
1006 ? UseInfo::PointerInt()
1007 : UseInfo::Any();
1008 EnqueueInput(node, i, use_info);
1009 }
1010 } else if (lower()) {
1011 Zone* zone = jsgraph_->zone();
1012 ZoneVector<MachineType>* types =
1013 new (zone->New(sizeof(ZoneVector<MachineType>)))
1014 ZoneVector<MachineType>(node->InputCount(), zone);
1015 for (int i = 0; i < node->InputCount(); i++) {
1016 Node* input = node->InputAt(i);
1017 NodeInfo* input_info = GetInfo(input);
1018 Type* input_type = TypeOf(input);
1019 // TODO(turbofan): Special treatment for ExternalPointer here,
1020 // to avoid incompatible truncations. We really need a story
1021 // for the JSFunction::entry field.
1022 if (input_type->Is(Type::ExternalPointer())) {
1023 (*types)[i] = MachineType::Pointer();
1024 } else {
1025 MachineRepresentation rep = input_type->IsInhabited()
1026 ? input_info->representation()
1027 : MachineRepresentation::kNone;
1028 MachineType machine_type(rep, DeoptValueSemanticOf(input_type));
1029 DCHECK(machine_type.representation() !=
1030 MachineRepresentation::kWord32 ||
1031 machine_type.semantic() == MachineSemantic::kInt32 ||
1032 machine_type.semantic() == MachineSemantic::kUint32);
1033 DCHECK(machine_type.representation() != MachineRepresentation::kBit ||
1034 input_type->Is(Type::Boolean()));
1035 (*types)[i] = machine_type;
1036 }
1037 }
1038 NodeProperties::ChangeOp(node,
1039 jsgraph_->common()->TypedObjectState(types));
1040 }
1041 SetOutput(node, MachineRepresentation::kTagged);
1042 }
1043
Int32Op(Node * node)1044 const Operator* Int32Op(Node* node) {
1045 return changer_->Int32OperatorFor(node->opcode());
1046 }
1047
Int32OverflowOp(Node * node)1048 const Operator* Int32OverflowOp(Node* node) {
1049 return changer_->Int32OverflowOperatorFor(node->opcode());
1050 }
1051
Uint32Op(Node * node)1052 const Operator* Uint32Op(Node* node) {
1053 return changer_->Uint32OperatorFor(node->opcode());
1054 }
1055
Uint32OverflowOp(Node * node)1056 const Operator* Uint32OverflowOp(Node* node) {
1057 return changer_->Uint32OverflowOperatorFor(node->opcode());
1058 }
1059
Float64Op(Node * node)1060 const Operator* Float64Op(Node* node) {
1061 return changer_->Float64OperatorFor(node->opcode());
1062 }
1063
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,Type * field_type,MachineRepresentation value_representation,Node * value)1064 WriteBarrierKind WriteBarrierKindFor(
1065 BaseTaggedness base_taggedness,
1066 MachineRepresentation field_representation, Type* field_type,
1067 MachineRepresentation value_representation, Node* value) {
1068 if (base_taggedness == kTaggedBase &&
1069 CanBeTaggedPointer(field_representation)) {
1070 Type* value_type = NodeProperties::GetType(value);
1071 if (field_representation == MachineRepresentation::kTaggedSigned ||
1072 value_representation == MachineRepresentation::kTaggedSigned) {
1073 // Write barriers are only for stores of heap objects.
1074 return kNoWriteBarrier;
1075 }
1076 if (field_type->Is(Type::BooleanOrNullOrUndefined()) ||
1077 value_type->Is(Type::BooleanOrNullOrUndefined())) {
1078 // Write barriers are not necessary when storing true, false, null or
1079 // undefined, because these special oddballs are always in the root set.
1080 return kNoWriteBarrier;
1081 }
1082 if (value_type->IsHeapConstant()) {
1083 Handle<HeapObject> value_object = value_type->AsHeapConstant()->Value();
1084 RootIndexMap root_index_map(jsgraph_->isolate());
1085 int root_index = root_index_map.Lookup(*value_object);
1086 if (root_index != RootIndexMap::kInvalidRootIndex &&
1087 jsgraph_->isolate()->heap()->RootIsImmortalImmovable(root_index)) {
1088 // Write barriers are unnecessary for immortal immovable roots.
1089 return kNoWriteBarrier;
1090 }
1091 if (value_object->IsMap()) {
1092 // Write barriers for storing maps are cheaper.
1093 return kMapWriteBarrier;
1094 }
1095 }
1096 if (field_representation == MachineRepresentation::kTaggedPointer ||
1097 value_representation == MachineRepresentation::kTaggedPointer) {
1098 // Write barriers for heap objects are cheaper.
1099 return kPointerWriteBarrier;
1100 }
1101 NumberMatcher m(value);
1102 if (m.HasValue()) {
1103 if (IsSmiDouble(m.Value())) {
1104 // Storing a smi doesn't need a write barrier.
1105 return kNoWriteBarrier;
1106 }
1107 // The NumberConstant will be represented as HeapNumber.
1108 return kPointerWriteBarrier;
1109 }
1110 return kFullWriteBarrier;
1111 }
1112 return kNoWriteBarrier;
1113 }
1114
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,int field_offset,Type * field_type,MachineRepresentation value_representation,Node * value)1115 WriteBarrierKind WriteBarrierKindFor(
1116 BaseTaggedness base_taggedness,
1117 MachineRepresentation field_representation, int field_offset,
1118 Type* field_type, MachineRepresentation value_representation,
1119 Node* value) {
1120 if (base_taggedness == kTaggedBase &&
1121 field_offset == HeapObject::kMapOffset) {
1122 return kMapWriteBarrier;
1123 }
1124 return WriteBarrierKindFor(base_taggedness, field_representation,
1125 field_type, value_representation, value);
1126 }
1127
graph() const1128 Graph* graph() const { return jsgraph_->graph(); }
common() const1129 CommonOperatorBuilder* common() const { return jsgraph_->common(); }
simplified() const1130 SimplifiedOperatorBuilder* simplified() const {
1131 return jsgraph_->simplified();
1132 }
1133
LowerToCheckedInt32Mul(Node * node,Truncation truncation,Type * input0_type,Type * input1_type)1134 void LowerToCheckedInt32Mul(Node* node, Truncation truncation,
1135 Type* input0_type, Type* input1_type) {
1136 // If one of the inputs is positive and/or truncation is being applied,
1137 // there is no need to return -0.
1138 CheckForMinusZeroMode mz_mode =
1139 truncation.IsUsedAsWord32() ||
1140 (input0_type->Is(Type::OrderedNumber()) &&
1141 input0_type->Min() > 0) ||
1142 (input1_type->Is(Type::OrderedNumber()) &&
1143 input1_type->Min() > 0)
1144 ? CheckForMinusZeroMode::kDontCheckForMinusZero
1145 : CheckForMinusZeroMode::kCheckForMinusZero;
1146
1147 NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
1148 }
1149
ChangeToInt32OverflowOp(Node * node)1150 void ChangeToInt32OverflowOp(Node* node) {
1151 NodeProperties::ChangeOp(node, Int32OverflowOp(node));
1152 }
1153
ChangeToUint32OverflowOp(Node * node)1154 void ChangeToUint32OverflowOp(Node* node) {
1155 NodeProperties::ChangeOp(node, Uint32OverflowOp(node));
1156 }
1157
VisitSpeculativeAdditiveOp(Node * node,Truncation truncation,SimplifiedLowering * lowering)1158 void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
1159 SimplifiedLowering* lowering) {
1160 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we can
1161 // only eliminate an unused speculative number operation if we know that
1162 // the inputs are PlainPrimitive, which excludes everything that's might
1163 // have side effects or throws during a ToNumber conversion.
1164 if (BothInputsAre(node, Type::PlainPrimitive())) {
1165 if (truncation.IsUnused()) return VisitUnused(node);
1166 }
1167 if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
1168 (GetUpperBound(node)->Is(Type::Signed32()) ||
1169 GetUpperBound(node)->Is(Type::Unsigned32()) ||
1170 truncation.IsUsedAsWord32())) {
1171 // => Int32Add/Sub
1172 VisitWord32TruncatingBinop(node);
1173 if (lower()) ChangeToPureOp(node, Int32Op(node));
1174 return;
1175 }
1176
1177 // Try to use type feedback.
1178 NumberOperationHint hint = NumberOperationHintOf(node->op());
1179
1180 // Handle the case when no int32 checks on inputs are necessary
1181 // (but an overflow check is needed on the output).
1182 if (BothInputsAre(node, Type::Signed32()) ||
1183 (BothInputsAre(node, Type::Signed32OrMinusZero()) &&
1184 NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger))) {
1185 // If both the inputs the feedback are int32, use the overflow op.
1186 if (hint == NumberOperationHint::kSignedSmall ||
1187 hint == NumberOperationHint::kSigned32) {
1188 VisitBinop(node, UseInfo::TruncatingWord32(),
1189 MachineRepresentation::kWord32, Type::Signed32());
1190 if (lower()) ChangeToInt32OverflowOp(node);
1191 return;
1192 }
1193 }
1194
1195 if (hint == NumberOperationHint::kSignedSmall ||
1196 hint == NumberOperationHint::kSigned32) {
1197 UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint);
1198 // For CheckedInt32Add and CheckedInt32Sub, we don't need to do
1199 // a minus zero check for the right hand side, since we already
1200 // know that the left hand side is a proper Signed32 value,
1201 // potentially guarded by a check.
1202 UseInfo right_use = CheckedUseInfoAsWord32FromHint(
1203 hint, CheckForMinusZeroMode::kDontCheckForMinusZero);
1204 VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32,
1205 Type::Signed32());
1206 if (lower()) ChangeToInt32OverflowOp(node);
1207 return;
1208 }
1209
1210 // default case => Float64Add/Sub
1211 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1212 MachineRepresentation::kFloat64, Type::Number());
1213 if (lower()) {
1214 ChangeToPureOp(node, Float64Op(node));
1215 }
1216 return;
1217 }
1218
VisitSpeculativeNumberModulus(Node * node,Truncation truncation,SimplifiedLowering * lowering)1219 void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
1220 SimplifiedLowering* lowering) {
1221 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1222 // can only eliminate an unused speculative number operation if we know
1223 // that the inputs are PlainPrimitive, which excludes everything that's
1224 // might have side effects or throws during a ToNumber conversion.
1225 if (BothInputsAre(node, Type::PlainPrimitive())) {
1226 if (truncation.IsUnused()) return VisitUnused(node);
1227 }
1228 if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1229 (truncation.IsUsedAsWord32() ||
1230 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1231 // => unsigned Uint32Mod
1232 VisitWord32TruncatingBinop(node);
1233 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1234 return;
1235 }
1236 if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1237 (truncation.IsUsedAsWord32() ||
1238 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1239 // => signed Int32Mod
1240 VisitWord32TruncatingBinop(node);
1241 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1242 return;
1243 }
1244
1245 // Try to use type feedback.
1246 NumberOperationHint hint = NumberOperationHintOf(node->op());
1247
1248 // Handle the case when no uint32 checks on inputs are necessary
1249 // (but an overflow check is needed on the output).
1250 if (BothInputsAreUnsigned32(node)) {
1251 if (hint == NumberOperationHint::kSignedSmall ||
1252 hint == NumberOperationHint::kSigned32) {
1253 VisitBinop(node, UseInfo::TruncatingWord32(),
1254 MachineRepresentation::kWord32, Type::Unsigned32());
1255 if (lower()) ChangeToUint32OverflowOp(node);
1256 return;
1257 }
1258 }
1259
1260 // Handle the case when no int32 checks on inputs are necessary
1261 // (but an overflow check is needed on the output).
1262 if (BothInputsAre(node, Type::Signed32())) {
1263 // If both the inputs the feedback are int32, use the overflow op.
1264 if (hint == NumberOperationHint::kSignedSmall ||
1265 hint == NumberOperationHint::kSigned32) {
1266 VisitBinop(node, UseInfo::TruncatingWord32(),
1267 MachineRepresentation::kWord32, Type::Signed32());
1268 if (lower()) ChangeToInt32OverflowOp(node);
1269 return;
1270 }
1271 }
1272
1273 if (hint == NumberOperationHint::kSignedSmall ||
1274 hint == NumberOperationHint::kSigned32) {
1275 // If the result is truncated, we only need to check the inputs.
1276 if (truncation.IsUsedAsWord32()) {
1277 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1278 MachineRepresentation::kWord32);
1279 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1280 } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
1281 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1282 MachineRepresentation::kWord32, Type::Unsigned32());
1283 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1284 } else {
1285 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1286 MachineRepresentation::kWord32, Type::Signed32());
1287 if (lower()) ChangeToInt32OverflowOp(node);
1288 }
1289 return;
1290 }
1291
1292 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1293 TypeOf(node->InputAt(1))->Is(Type::Unsigned32()) &&
1294 (truncation.IsUsedAsWord32() ||
1295 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1296 // We can only promise Float64 truncation here, as the decision is
1297 // based on the feedback types of the inputs.
1298 VisitBinop(node,
1299 UseInfo(MachineRepresentation::kWord32, Truncation::Float64()),
1300 MachineRepresentation::kWord32, Type::Number());
1301 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1302 return;
1303 }
1304 if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1305 TypeOf(node->InputAt(1))->Is(Type::Signed32()) &&
1306 (truncation.IsUsedAsWord32() ||
1307 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1308 // We can only promise Float64 truncation here, as the decision is
1309 // based on the feedback types of the inputs.
1310 VisitBinop(node,
1311 UseInfo(MachineRepresentation::kWord32, Truncation::Float64()),
1312 MachineRepresentation::kWord32, Type::Number());
1313 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1314 return;
1315 }
1316 // default case => Float64Mod
1317 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1318 MachineRepresentation::kFloat64, Type::Number());
1319 if (lower()) ChangeToPureOp(node, Float64Op(node));
1320 return;
1321 }
1322
VisitOsrGuard(Node * node)1323 void VisitOsrGuard(Node* node) {
1324 VisitInputs(node);
1325
1326 // Insert a dynamic check for the OSR value type if necessary.
1327 switch (OsrGuardTypeOf(node->op())) {
1328 case OsrGuardType::kUninitialized:
1329 // At this point, we should always have a type for the OsrValue.
1330 UNREACHABLE();
1331 break;
1332 case OsrGuardType::kSignedSmall:
1333 if (lower()) {
1334 NodeProperties::ChangeOp(node,
1335 simplified()->CheckedTaggedToTaggedSigned());
1336 }
1337 return SetOutput(node, MachineRepresentation::kTaggedSigned);
1338 case OsrGuardType::kAny: // Nothing to check.
1339 if (lower()) {
1340 DeferReplacement(node, node->InputAt(0));
1341 }
1342 return SetOutput(node, MachineRepresentation::kTagged);
1343 }
1344 UNREACHABLE();
1345 }
1346
1347 // Dispatching routine for visiting the node {node} with the usage {use}.
1348 // Depending on the operator, propagate new usage info to the inputs.
VisitNode(Node * node,Truncation truncation,SimplifiedLowering * lowering)1349 void VisitNode(Node* node, Truncation truncation,
1350 SimplifiedLowering* lowering) {
1351 // Unconditionally eliminate unused pure nodes (only relevant if there's
1352 // a pure operation in between two effectful ones, where the last one
1353 // is unused).
1354 // Note: We must not do this for constants, as they are cached and we
1355 // would thus kill the cached {node} during lowering (i.e. replace all
1356 // uses with Dead), but at that point some node lowering might have
1357 // already taken the constant {node} from the cache (while it was in
1358 // a sane state still) and we would afterwards replace that use with
1359 // Dead as well.
1360 if (node->op()->ValueInputCount() > 0 &&
1361 node->op()->HasProperty(Operator::kPure)) {
1362 if (truncation.IsUnused()) return VisitUnused(node);
1363 }
1364 switch (node->opcode()) {
1365 //------------------------------------------------------------------
1366 // Common operators.
1367 //------------------------------------------------------------------
1368 case IrOpcode::kStart:
1369 // We use Start as a terminator for the frame state chain, so even
1370 // tho Start doesn't really produce a value, we have to say Tagged
1371 // here, otherwise the input conversion will fail.
1372 return VisitLeaf(node, MachineRepresentation::kTagged);
1373 case IrOpcode::kParameter:
1374 // TODO(titzer): use representation from linkage.
1375 return VisitUnop(node, UseInfo::None(), MachineRepresentation::kTagged);
1376 case IrOpcode::kInt32Constant:
1377 return VisitLeaf(node, MachineRepresentation::kWord32);
1378 case IrOpcode::kInt64Constant:
1379 return VisitLeaf(node, MachineRepresentation::kWord64);
1380 case IrOpcode::kExternalConstant:
1381 return VisitLeaf(node, MachineType::PointerRepresentation());
1382 case IrOpcode::kNumberConstant:
1383 return VisitLeaf(node, MachineRepresentation::kTagged);
1384 case IrOpcode::kHeapConstant:
1385 return VisitLeaf(node, MachineRepresentation::kTaggedPointer);
1386 case IrOpcode::kPointerConstant: {
1387 VisitLeaf(node, MachineType::PointerRepresentation());
1388 if (lower()) {
1389 intptr_t const value = OpParameter<intptr_t>(node);
1390 DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
1391 }
1392 return;
1393 }
1394
1395 case IrOpcode::kBranch:
1396 ProcessInput(node, 0, UseInfo::Bool());
1397 EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1398 return;
1399 case IrOpcode::kSwitch:
1400 ProcessInput(node, 0, UseInfo::TruncatingWord32());
1401 EnqueueInput(node, NodeProperties::FirstControlIndex(node));
1402 return;
1403 case IrOpcode::kSelect:
1404 return VisitSelect(node, truncation, lowering);
1405 case IrOpcode::kPhi:
1406 return VisitPhi(node, truncation, lowering);
1407 case IrOpcode::kCall:
1408 return VisitCall(node, lowering);
1409
1410 //------------------------------------------------------------------
1411 // JavaScript operators.
1412 //------------------------------------------------------------------
1413 case IrOpcode::kJSToBoolean: {
1414 if (truncation.IsUsedAsBool()) {
1415 ProcessInput(node, 0, UseInfo::Bool());
1416 ProcessInput(node, 1, UseInfo::None());
1417 SetOutput(node, MachineRepresentation::kBit);
1418 if (lower()) DeferReplacement(node, node->InputAt(0));
1419 } else {
1420 VisitInputs(node);
1421 SetOutput(node, MachineRepresentation::kTaggedPointer);
1422 }
1423 return;
1424 }
1425 case IrOpcode::kJSToNumber: {
1426 VisitInputs(node);
1427 // TODO(bmeurer): Optimize somewhat based on input type?
1428 if (truncation.IsUsedAsWord32()) {
1429 SetOutput(node, MachineRepresentation::kWord32);
1430 if (lower()) lowering->DoJSToNumberTruncatesToWord32(node, this);
1431 } else if (truncation.IsUsedAsFloat64()) {
1432 SetOutput(node, MachineRepresentation::kFloat64);
1433 if (lower()) lowering->DoJSToNumberTruncatesToFloat64(node, this);
1434 } else {
1435 SetOutput(node, MachineRepresentation::kTagged);
1436 }
1437 return;
1438 }
1439
1440 //------------------------------------------------------------------
1441 // Simplified operators.
1442 //------------------------------------------------------------------
1443 case IrOpcode::kBooleanNot: {
1444 if (lower()) {
1445 NodeInfo* input_info = GetInfo(node->InputAt(0));
1446 if (input_info->representation() == MachineRepresentation::kBit) {
1447 // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
1448 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
1449 NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
1450 } else {
1451 DCHECK(CanBeTaggedPointer(input_info->representation()));
1452 // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
1453 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
1454 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
1455 }
1456 } else {
1457 // No input representation requirement; adapt during lowering.
1458 ProcessInput(node, 0, UseInfo::AnyTruncatingToBool());
1459 SetOutput(node, MachineRepresentation::kBit);
1460 }
1461 return;
1462 }
1463 case IrOpcode::kNumberEqual: {
1464 Type* const lhs_type = TypeOf(node->InputAt(0));
1465 Type* const rhs_type = TypeOf(node->InputAt(1));
1466 // Number comparisons reduce to integer comparisons for integer inputs.
1467 if ((lhs_type->Is(Type::Unsigned32()) &&
1468 rhs_type->Is(Type::Unsigned32())) ||
1469 (lhs_type->Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1470 rhs_type->Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1471 OneInputCannotBe(node, type_cache_.kZeroish))) {
1472 // => unsigned Int32Cmp
1473 VisitBinop(node, UseInfo::TruncatingWord32(),
1474 MachineRepresentation::kBit);
1475 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1476 return;
1477 }
1478 if ((lhs_type->Is(Type::Signed32()) &&
1479 rhs_type->Is(Type::Signed32())) ||
1480 (lhs_type->Is(Type::Signed32OrMinusZeroOrNaN()) &&
1481 rhs_type->Is(Type::Signed32OrMinusZeroOrNaN()) &&
1482 OneInputCannotBe(node, type_cache_.kZeroish))) {
1483 // => signed Int32Cmp
1484 VisitBinop(node, UseInfo::TruncatingWord32(),
1485 MachineRepresentation::kBit);
1486 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1487 return;
1488 }
1489 // => Float64Cmp
1490 VisitBinop(node, UseInfo::TruncatingFloat64(),
1491 MachineRepresentation::kBit);
1492 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1493 return;
1494 }
1495 case IrOpcode::kNumberLessThan:
1496 case IrOpcode::kNumberLessThanOrEqual: {
1497 // Number comparisons reduce to integer comparisons for integer inputs.
1498 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1499 TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
1500 // => unsigned Int32Cmp
1501 VisitBinop(node, UseInfo::TruncatingWord32(),
1502 MachineRepresentation::kBit);
1503 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1504 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1505 TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
1506 // => signed Int32Cmp
1507 VisitBinop(node, UseInfo::TruncatingWord32(),
1508 MachineRepresentation::kBit);
1509 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1510 } else {
1511 // => Float64Cmp
1512 VisitBinop(node, UseInfo::TruncatingFloat64(),
1513 MachineRepresentation::kBit);
1514 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1515 }
1516 return;
1517 }
1518
1519 case IrOpcode::kSpeculativeNumberAdd:
1520 case IrOpcode::kSpeculativeNumberSubtract:
1521 return VisitSpeculativeAdditiveOp(node, truncation, lowering);
1522
1523 case IrOpcode::kSpeculativeNumberLessThan:
1524 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
1525 case IrOpcode::kSpeculativeNumberEqual: {
1526 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1527 // can only eliminate an unused speculative number operation if we know
1528 // that the inputs are PlainPrimitive, which excludes everything that's
1529 // might have side effects or throws during a ToNumber conversion.
1530 if (BothInputsAre(node, Type::PlainPrimitive())) {
1531 if (truncation.IsUnused()) return VisitUnused(node);
1532 }
1533 // Number comparisons reduce to integer comparisons for integer inputs.
1534 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1535 TypeOf(node->InputAt(1))->Is(Type::Unsigned32())) {
1536 // => unsigned Int32Cmp
1537 VisitBinop(node, UseInfo::TruncatingWord32(),
1538 MachineRepresentation::kBit);
1539 if (lower()) ChangeToPureOp(node, Uint32Op(node));
1540 return;
1541 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1542 TypeOf(node->InputAt(1))->Is(Type::Signed32())) {
1543 // => signed Int32Cmp
1544 VisitBinop(node, UseInfo::TruncatingWord32(),
1545 MachineRepresentation::kBit);
1546 if (lower()) ChangeToPureOp(node, Int32Op(node));
1547 return;
1548 }
1549 // Try to use type feedback.
1550 NumberOperationHint hint = NumberOperationHintOf(node->op());
1551 switch (hint) {
1552 case NumberOperationHint::kSignedSmall:
1553 case NumberOperationHint::kSigned32:
1554 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1555 MachineRepresentation::kBit);
1556 if (lower()) ChangeToPureOp(node, Int32Op(node));
1557 return;
1558 case NumberOperationHint::kNumber:
1559 case NumberOperationHint::kNumberOrOddball:
1560 VisitBinop(node, CheckedUseInfoAsFloat64FromHint(hint),
1561 MachineRepresentation::kBit);
1562 if (lower()) ChangeToPureOp(node, Float64Op(node));
1563 return;
1564 }
1565 UNREACHABLE();
1566 return;
1567 }
1568
1569 case IrOpcode::kNumberAdd:
1570 case IrOpcode::kNumberSubtract: {
1571 if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
1572 (GetUpperBound(node)->Is(Type::Signed32()) ||
1573 GetUpperBound(node)->Is(Type::Unsigned32()) ||
1574 truncation.IsUsedAsWord32())) {
1575 // => Int32Add/Sub
1576 VisitWord32TruncatingBinop(node);
1577 if (lower()) ChangeToPureOp(node, Int32Op(node));
1578 } else {
1579 // => Float64Add/Sub
1580 VisitFloat64Binop(node);
1581 if (lower()) ChangeToPureOp(node, Float64Op(node));
1582 }
1583 return;
1584 }
1585 case IrOpcode::kSpeculativeNumberMultiply: {
1586 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1587 // can only eliminate an unused speculative number operation if we know
1588 // that the inputs are PlainPrimitive, which excludes everything that's
1589 // might have side effects or throws during a ToNumber conversion.
1590 if (BothInputsAre(node, Type::PlainPrimitive())) {
1591 if (truncation.IsUnused()) return VisitUnused(node);
1592 }
1593 if (BothInputsAre(node, Type::Integral32()) &&
1594 (NodeProperties::GetType(node)->Is(Type::Signed32()) ||
1595 NodeProperties::GetType(node)->Is(Type::Unsigned32()) ||
1596 (truncation.IsUsedAsWord32() &&
1597 NodeProperties::GetType(node)->Is(
1598 type_cache_.kSafeIntegerOrMinusZero)))) {
1599 // Multiply reduces to Int32Mul if the inputs are integers, and
1600 // (a) the output is either known to be Signed32, or
1601 // (b) the output is known to be Unsigned32, or
1602 // (c) the uses are truncating and the result is in the safe
1603 // integer range.
1604 VisitWord32TruncatingBinop(node);
1605 if (lower()) ChangeToPureOp(node, Int32Op(node));
1606 return;
1607 }
1608 // Try to use type feedback.
1609 NumberOperationHint hint = NumberOperationHintOf(node->op());
1610 Type* input0_type = TypeOf(node->InputAt(0));
1611 Type* input1_type = TypeOf(node->InputAt(1));
1612
1613 // Handle the case when no int32 checks on inputs are necessary
1614 // (but an overflow check is needed on the output).
1615 if (BothInputsAre(node, Type::Signed32())) {
1616 // If both the inputs the feedback are int32, use the overflow op.
1617 if (hint == NumberOperationHint::kSignedSmall ||
1618 hint == NumberOperationHint::kSigned32) {
1619 VisitBinop(node, UseInfo::TruncatingWord32(),
1620 MachineRepresentation::kWord32, Type::Signed32());
1621 if (lower()) {
1622 LowerToCheckedInt32Mul(node, truncation, input0_type,
1623 input1_type);
1624 }
1625 return;
1626 }
1627 }
1628
1629 if (hint == NumberOperationHint::kSignedSmall ||
1630 hint == NumberOperationHint::kSigned32) {
1631 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1632 MachineRepresentation::kWord32, Type::Signed32());
1633 if (lower()) {
1634 LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type);
1635 }
1636 return;
1637 }
1638
1639 // Checked float64 x float64 => float64
1640 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1641 MachineRepresentation::kFloat64, Type::Number());
1642 if (lower()) ChangeToPureOp(node, Float64Op(node));
1643 return;
1644 }
1645 case IrOpcode::kNumberMultiply: {
1646 if (BothInputsAre(node, Type::Integral32()) &&
1647 (NodeProperties::GetType(node)->Is(Type::Signed32()) ||
1648 NodeProperties::GetType(node)->Is(Type::Unsigned32()) ||
1649 (truncation.IsUsedAsWord32() &&
1650 NodeProperties::GetType(node)->Is(
1651 type_cache_.kSafeIntegerOrMinusZero)))) {
1652 // Multiply reduces to Int32Mul if the inputs are integers, and
1653 // (a) the output is either known to be Signed32, or
1654 // (b) the output is known to be Unsigned32, or
1655 // (c) the uses are truncating and the result is in the safe
1656 // integer range.
1657 VisitWord32TruncatingBinop(node);
1658 if (lower()) ChangeToPureOp(node, Int32Op(node));
1659 return;
1660 }
1661 // Number x Number => Float64Mul
1662 VisitFloat64Binop(node);
1663 if (lower()) ChangeToPureOp(node, Float64Op(node));
1664 return;
1665 }
1666 case IrOpcode::kSpeculativeNumberDivide: {
1667 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1668 // can only eliminate an unused speculative number operation if we know
1669 // that the inputs are PlainPrimitive, which excludes everything that's
1670 // might have side effects or throws during a ToNumber conversion.
1671 if (BothInputsAre(node, Type::PlainPrimitive())) {
1672 if (truncation.IsUnused()) return VisitUnused(node);
1673 }
1674 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
1675 // => unsigned Uint32Div
1676 VisitWord32TruncatingBinop(node);
1677 if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
1678 return;
1679 }
1680 if (BothInputsAreSigned32(node)) {
1681 if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
1682 // => signed Int32Div
1683 VisitWord32TruncatingBinop(node);
1684 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1685 return;
1686 }
1687 if (truncation.IsUsedAsWord32()) {
1688 // => signed Int32Div
1689 VisitWord32TruncatingBinop(node);
1690 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1691 return;
1692 }
1693 }
1694
1695 // Try to use type feedback.
1696 NumberOperationHint hint = NumberOperationHintOf(node->op());
1697
1698 // Handle the case when no uint32 checks on inputs are necessary
1699 // (but an overflow check is needed on the output).
1700 if (BothInputsAreUnsigned32(node)) {
1701 if (hint == NumberOperationHint::kSignedSmall ||
1702 hint == NumberOperationHint::kSigned32) {
1703 VisitBinop(node, UseInfo::TruncatingWord32(),
1704 MachineRepresentation::kWord32, Type::Unsigned32());
1705 if (lower()) ChangeToUint32OverflowOp(node);
1706 return;
1707 }
1708 }
1709
1710 // Handle the case when no int32 checks on inputs are necessary
1711 // (but an overflow check is needed on the output).
1712 if (BothInputsAreSigned32(node)) {
1713 // If both the inputs the feedback are int32, use the overflow op.
1714 if (hint == NumberOperationHint::kSignedSmall ||
1715 hint == NumberOperationHint::kSigned32) {
1716 VisitBinop(node, UseInfo::TruncatingWord32(),
1717 MachineRepresentation::kWord32, Type::Signed32());
1718 if (lower()) ChangeToInt32OverflowOp(node);
1719 return;
1720 }
1721 }
1722
1723 if (hint == NumberOperationHint::kSignedSmall ||
1724 hint == NumberOperationHint::kSigned32) {
1725 // If the result is truncated, we only need to check the inputs.
1726 if (truncation.IsUsedAsWord32()) {
1727 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1728 MachineRepresentation::kWord32);
1729 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1730 } else {
1731 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1732 MachineRepresentation::kWord32, Type::Signed32());
1733 if (lower()) ChangeToInt32OverflowOp(node);
1734 }
1735 return;
1736 }
1737
1738 // default case => Float64Div
1739 VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
1740 MachineRepresentation::kFloat64, Type::Number());
1741 if (lower()) ChangeToPureOp(node, Float64Op(node));
1742 return;
1743 }
1744 case IrOpcode::kNumberDivide: {
1745 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
1746 // => unsigned Uint32Div
1747 VisitWord32TruncatingBinop(node);
1748 if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
1749 return;
1750 }
1751 if (BothInputsAreSigned32(node)) {
1752 if (NodeProperties::GetType(node)->Is(Type::Signed32())) {
1753 // => signed Int32Div
1754 VisitWord32TruncatingBinop(node);
1755 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1756 return;
1757 }
1758 if (truncation.IsUsedAsWord32()) {
1759 // => signed Int32Div
1760 VisitWord32TruncatingBinop(node);
1761 if (lower()) DeferReplacement(node, lowering->Int32Div(node));
1762 return;
1763 }
1764 }
1765 // Number x Number => Float64Div
1766 VisitFloat64Binop(node);
1767 if (lower()) ChangeToPureOp(node, Float64Op(node));
1768 return;
1769 }
1770 case IrOpcode::kSpeculativeNumberModulus:
1771 return VisitSpeculativeNumberModulus(node, truncation, lowering);
1772 case IrOpcode::kNumberModulus: {
1773 if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1774 (truncation.IsUsedAsWord32() ||
1775 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1776 // => unsigned Uint32Mod
1777 VisitWord32TruncatingBinop(node);
1778 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1779 return;
1780 }
1781 if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1782 (truncation.IsUsedAsWord32() ||
1783 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1784 // => signed Int32Mod
1785 VisitWord32TruncatingBinop(node);
1786 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1787 return;
1788 }
1789 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32()) &&
1790 TypeOf(node->InputAt(1))->Is(Type::Unsigned32()) &&
1791 (truncation.IsUsedAsWord32() ||
1792 NodeProperties::GetType(node)->Is(Type::Unsigned32()))) {
1793 // We can only promise Float64 truncation here, as the decision is
1794 // based on the feedback types of the inputs.
1795 VisitBinop(node, UseInfo(MachineRepresentation::kWord32,
1796 Truncation::Float64()),
1797 MachineRepresentation::kWord32);
1798 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node));
1799 return;
1800 }
1801 if (TypeOf(node->InputAt(0))->Is(Type::Signed32()) &&
1802 TypeOf(node->InputAt(1))->Is(Type::Signed32()) &&
1803 (truncation.IsUsedAsWord32() ||
1804 NodeProperties::GetType(node)->Is(Type::Signed32()))) {
1805 // We can only promise Float64 truncation here, as the decision is
1806 // based on the feedback types of the inputs.
1807 VisitBinop(node, UseInfo(MachineRepresentation::kWord32,
1808 Truncation::Float64()),
1809 MachineRepresentation::kWord32);
1810 if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
1811 return;
1812 }
1813 // default case => Float64Mod
1814 VisitFloat64Binop(node);
1815 if (lower()) ChangeToPureOp(node, Float64Op(node));
1816 return;
1817 }
1818 case IrOpcode::kNumberBitwiseOr:
1819 case IrOpcode::kNumberBitwiseXor:
1820 case IrOpcode::kNumberBitwiseAnd: {
1821 VisitWord32TruncatingBinop(node);
1822 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node));
1823 return;
1824 }
1825 case IrOpcode::kSpeculativeNumberBitwiseOr:
1826 case IrOpcode::kSpeculativeNumberBitwiseXor:
1827 case IrOpcode::kSpeculativeNumberBitwiseAnd:
1828 VisitSpeculativeInt32Binop(node);
1829 if (lower()) {
1830 ChangeToPureOp(node, Int32Op(node));
1831 }
1832 return;
1833 case IrOpcode::kNumberShiftLeft: {
1834 Type* rhs_type = GetUpperBound(node->InputAt(1));
1835 VisitBinop(node, UseInfo::TruncatingWord32(),
1836 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1837 if (lower()) {
1838 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
1839 }
1840 return;
1841 }
1842 case IrOpcode::kSpeculativeNumberShiftLeft: {
1843 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1844 // can only eliminate an unused speculative number operation if we know
1845 // that the inputs are PlainPrimitive, which excludes everything that's
1846 // might have side effects or throws during a ToNumber conversion.
1847 if (BothInputsAre(node, Type::PlainPrimitive())) {
1848 if (truncation.IsUnused()) return VisitUnused(node);
1849 }
1850 if (BothInputsAre(node, Type::NumberOrOddball())) {
1851 Type* rhs_type = GetUpperBound(node->InputAt(1));
1852 VisitBinop(node, UseInfo::TruncatingWord32(),
1853 UseInfo::TruncatingWord32(),
1854 MachineRepresentation::kWord32);
1855 if (lower()) {
1856 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
1857 }
1858 return;
1859 }
1860 NumberOperationHint hint = NumberOperationHintOf(node->op());
1861 Type* rhs_type = GetUpperBound(node->InputAt(1));
1862 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1863 MachineRepresentation::kWord32, Type::Signed32());
1864 if (lower()) {
1865 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
1866 }
1867 return;
1868 }
1869 case IrOpcode::kNumberShiftRight: {
1870 Type* rhs_type = GetUpperBound(node->InputAt(1));
1871 VisitBinop(node, UseInfo::TruncatingWord32(),
1872 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1873 if (lower()) {
1874 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
1875 }
1876 return;
1877 }
1878 case IrOpcode::kSpeculativeNumberShiftRight: {
1879 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1880 // can only eliminate an unused speculative number operation if we know
1881 // that the inputs are PlainPrimitive, which excludes everything that's
1882 // might have side effects or throws during a ToNumber conversion.
1883 if (BothInputsAre(node, Type::PlainPrimitive())) {
1884 if (truncation.IsUnused()) return VisitUnused(node);
1885 }
1886 if (BothInputsAre(node, Type::NumberOrOddball())) {
1887 Type* rhs_type = GetUpperBound(node->InputAt(1));
1888 VisitBinop(node, UseInfo::TruncatingWord32(),
1889 UseInfo::TruncatingWord32(),
1890 MachineRepresentation::kWord32);
1891 if (lower()) {
1892 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
1893 }
1894 return;
1895 }
1896 NumberOperationHint hint = NumberOperationHintOf(node->op());
1897 Type* rhs_type = GetUpperBound(node->InputAt(1));
1898 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1899 MachineRepresentation::kWord32, Type::Signed32());
1900 if (lower()) {
1901 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
1902 }
1903 return;
1904 }
1905 case IrOpcode::kNumberShiftRightLogical: {
1906 Type* rhs_type = GetUpperBound(node->InputAt(1));
1907 VisitBinop(node, UseInfo::TruncatingWord32(),
1908 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1909 if (lower()) {
1910 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
1911 }
1912 return;
1913 }
1914 case IrOpcode::kSpeculativeNumberShiftRightLogical: {
1915 // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we
1916 // can only eliminate an unused speculative number operation if we know
1917 // that the inputs are PlainPrimitive, which excludes everything that's
1918 // might have side effects or throws during a ToNumber conversion.
1919 if (BothInputsAre(node, Type::PlainPrimitive())) {
1920 if (truncation.IsUnused()) return VisitUnused(node);
1921 }
1922 if (BothInputsAre(node, Type::NumberOrOddball())) {
1923 Type* rhs_type = GetUpperBound(node->InputAt(1));
1924 VisitBinop(node, UseInfo::TruncatingWord32(),
1925 UseInfo::TruncatingWord32(),
1926 MachineRepresentation::kWord32);
1927 if (lower()) {
1928 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
1929 }
1930 return;
1931 }
1932 NumberOperationHint hint = NumberOperationHintOf(node->op());
1933 Type* rhs_type = GetUpperBound(node->InputAt(1));
1934 VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
1935 MachineRepresentation::kWord32, Type::Unsigned32());
1936 if (lower()) {
1937 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
1938 }
1939 return;
1940 }
1941 case IrOpcode::kNumberAbs: {
1942 if (TypeOf(node->InputAt(0))->Is(Type::Unsigned32())) {
1943 VisitUnop(node, UseInfo::TruncatingWord32(),
1944 MachineRepresentation::kWord32);
1945 if (lower()) DeferReplacement(node, node->InputAt(0));
1946 } else if (TypeOf(node->InputAt(0))->Is(Type::Signed32())) {
1947 VisitUnop(node, UseInfo::TruncatingWord32(),
1948 MachineRepresentation::kWord32);
1949 if (lower()) DeferReplacement(node, lowering->Int32Abs(node));
1950 } else if (TypeOf(node->InputAt(0))
1951 ->Is(type_cache_.kPositiveIntegerOrMinusZeroOrNaN)) {
1952 VisitUnop(node, UseInfo::TruncatingFloat64(),
1953 MachineRepresentation::kFloat64);
1954 if (lower()) DeferReplacement(node, node->InputAt(0));
1955 } else {
1956 VisitUnop(node, UseInfo::TruncatingFloat64(),
1957 MachineRepresentation::kFloat64);
1958 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1959 }
1960 return;
1961 }
1962 case IrOpcode::kNumberClz32: {
1963 VisitUnop(node, UseInfo::TruncatingWord32(),
1964 MachineRepresentation::kWord32);
1965 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1966 return;
1967 }
1968 case IrOpcode::kNumberImul: {
1969 VisitBinop(node, UseInfo::TruncatingWord32(),
1970 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1971 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node));
1972 return;
1973 }
1974 case IrOpcode::kNumberFround: {
1975 VisitUnop(node, UseInfo::TruncatingFloat64(),
1976 MachineRepresentation::kFloat32);
1977 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
1978 return;
1979 }
1980 case IrOpcode::kNumberMax: {
1981 // TODO(turbofan): We should consider feedback types here as well.
1982 if (BothInputsAreUnsigned32(node)) {
1983 VisitWord32TruncatingBinop(node);
1984 if (lower()) {
1985 lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
1986 MachineRepresentation::kWord32);
1987 }
1988 } else if (BothInputsAreSigned32(node)) {
1989 VisitWord32TruncatingBinop(node);
1990 if (lower()) {
1991 lowering->DoMax(node, lowering->machine()->Int32LessThan(),
1992 MachineRepresentation::kWord32);
1993 }
1994 } else if (BothInputsAre(node, Type::PlainNumber())) {
1995 VisitFloat64Binop(node);
1996 if (lower()) {
1997 lowering->DoMax(node, lowering->machine()->Float64LessThan(),
1998 MachineRepresentation::kFloat64);
1999 }
2000 } else {
2001 VisitFloat64Binop(node);
2002 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2003 }
2004 return;
2005 }
2006 case IrOpcode::kNumberMin: {
2007 // TODO(turbofan): We should consider feedback types here as well.
2008 if (BothInputsAreUnsigned32(node)) {
2009 VisitWord32TruncatingBinop(node);
2010 if (lower()) {
2011 lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
2012 MachineRepresentation::kWord32);
2013 }
2014 } else if (BothInputsAreSigned32(node)) {
2015 VisitWord32TruncatingBinop(node);
2016 if (lower()) {
2017 lowering->DoMin(node, lowering->machine()->Int32LessThan(),
2018 MachineRepresentation::kWord32);
2019 }
2020 } else if (BothInputsAre(node, Type::PlainNumber())) {
2021 VisitFloat64Binop(node);
2022 if (lower()) {
2023 lowering->DoMin(node, lowering->machine()->Float64LessThan(),
2024 MachineRepresentation::kFloat64);
2025 }
2026 } else {
2027 VisitFloat64Binop(node);
2028 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2029 }
2030 return;
2031 }
2032 case IrOpcode::kNumberAtan2:
2033 case IrOpcode::kNumberPow: {
2034 VisitBinop(node, UseInfo::TruncatingFloat64(),
2035 MachineRepresentation::kFloat64);
2036 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2037 return;
2038 }
2039 case IrOpcode::kNumberAcos:
2040 case IrOpcode::kNumberAcosh:
2041 case IrOpcode::kNumberAsin:
2042 case IrOpcode::kNumberAsinh:
2043 case IrOpcode::kNumberAtan:
2044 case IrOpcode::kNumberAtanh:
2045 case IrOpcode::kNumberCeil:
2046 case IrOpcode::kNumberCos:
2047 case IrOpcode::kNumberCosh:
2048 case IrOpcode::kNumberExp:
2049 case IrOpcode::kNumberExpm1:
2050 case IrOpcode::kNumberFloor:
2051 case IrOpcode::kNumberLog:
2052 case IrOpcode::kNumberLog1p:
2053 case IrOpcode::kNumberLog2:
2054 case IrOpcode::kNumberLog10:
2055 case IrOpcode::kNumberCbrt:
2056 case IrOpcode::kNumberSin:
2057 case IrOpcode::kNumberSinh:
2058 case IrOpcode::kNumberTan:
2059 case IrOpcode::kNumberTanh:
2060 case IrOpcode::kNumberTrunc: {
2061 VisitUnop(node, UseInfo::TruncatingFloat64(),
2062 MachineRepresentation::kFloat64);
2063 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2064 return;
2065 }
2066 case IrOpcode::kNumberRound: {
2067 VisitUnop(node, UseInfo::TruncatingFloat64(),
2068 MachineRepresentation::kFloat64);
2069 if (lower()) DeferReplacement(node, lowering->Float64Round(node));
2070 return;
2071 }
2072 case IrOpcode::kNumberSign: {
2073 if (InputIs(node, Type::Signed32())) {
2074 VisitUnop(node, UseInfo::TruncatingWord32(),
2075 MachineRepresentation::kWord32);
2076 if (lower()) DeferReplacement(node, lowering->Int32Sign(node));
2077 } else {
2078 VisitUnop(node, UseInfo::TruncatingFloat64(),
2079 MachineRepresentation::kFloat64);
2080 if (lower()) DeferReplacement(node, lowering->Float64Sign(node));
2081 }
2082 return;
2083 }
2084 case IrOpcode::kNumberSqrt: {
2085 VisitUnop(node, UseInfo::TruncatingFloat64(),
2086 MachineRepresentation::kFloat64);
2087 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2088 return;
2089 }
2090 case IrOpcode::kNumberToBoolean: {
2091 Type* const input_type = TypeOf(node->InputAt(0));
2092 if (input_type->Is(Type::Integral32())) {
2093 VisitUnop(node, UseInfo::TruncatingWord32(),
2094 MachineRepresentation::kBit);
2095 if (lower()) lowering->DoIntegral32ToBit(node);
2096 } else if (input_type->Is(Type::OrderedNumber())) {
2097 VisitUnop(node, UseInfo::TruncatingFloat64(),
2098 MachineRepresentation::kBit);
2099 if (lower()) lowering->DoOrderedNumberToBit(node);
2100 } else {
2101 VisitUnop(node, UseInfo::TruncatingFloat64(),
2102 MachineRepresentation::kBit);
2103 if (lower()) lowering->DoNumberToBit(node);
2104 }
2105 return;
2106 }
2107 case IrOpcode::kNumberToInt32: {
2108 // Just change representation if necessary.
2109 VisitUnop(node, UseInfo::TruncatingWord32(),
2110 MachineRepresentation::kWord32);
2111 if (lower()) DeferReplacement(node, node->InputAt(0));
2112 return;
2113 }
2114 case IrOpcode::kNumberToUint32: {
2115 // Just change representation if necessary.
2116 VisitUnop(node, UseInfo::TruncatingWord32(),
2117 MachineRepresentation::kWord32);
2118 if (lower()) DeferReplacement(node, node->InputAt(0));
2119 return;
2120 }
2121 case IrOpcode::kNumberToUint8Clamped: {
2122 Type* const input_type = TypeOf(node->InputAt(0));
2123 if (input_type->Is(type_cache_.kUint8OrMinusZeroOrNaN)) {
2124 VisitUnop(node, UseInfo::TruncatingWord32(),
2125 MachineRepresentation::kWord32);
2126 if (lower()) DeferReplacement(node, node->InputAt(0));
2127 } else if (input_type->Is(Type::Unsigned32OrMinusZeroOrNaN())) {
2128 VisitUnop(node, UseInfo::TruncatingWord32(),
2129 MachineRepresentation::kWord32);
2130 if (lower()) lowering->DoUnsigned32ToUint8Clamped(node);
2131 } else if (input_type->Is(Type::Signed32OrMinusZeroOrNaN())) {
2132 VisitUnop(node, UseInfo::TruncatingWord32(),
2133 MachineRepresentation::kWord32);
2134 if (lower()) lowering->DoSigned32ToUint8Clamped(node);
2135 } else if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) {
2136 VisitUnop(node, UseInfo::TruncatingFloat64(),
2137 MachineRepresentation::kFloat64);
2138 if (lower()) lowering->DoIntegerToUint8Clamped(node);
2139 } else {
2140 VisitUnop(node, UseInfo::TruncatingFloat64(),
2141 MachineRepresentation::kFloat64);
2142 if (lower()) lowering->DoNumberToUint8Clamped(node);
2143 }
2144 return;
2145 }
2146 case IrOpcode::kReferenceEqual: {
2147 VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2148 if (lower()) {
2149 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
2150 }
2151 return;
2152 }
2153 case IrOpcode::kStringEqual:
2154 case IrOpcode::kStringLessThan:
2155 case IrOpcode::kStringLessThanOrEqual: {
2156 return VisitBinop(node, UseInfo::AnyTagged(),
2157 MachineRepresentation::kTaggedPointer);
2158 }
2159 case IrOpcode::kStringCharCodeAt: {
2160 VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
2161 MachineRepresentation::kWord32);
2162 return;
2163 }
2164 case IrOpcode::kStringFromCharCode: {
2165 VisitUnop(node, UseInfo::TruncatingWord32(),
2166 MachineRepresentation::kTaggedPointer);
2167 return;
2168 }
2169 case IrOpcode::kStringFromCodePoint: {
2170 VisitUnop(node, UseInfo::TruncatingWord32(),
2171 MachineRepresentation::kTaggedPointer);
2172 return;
2173 }
2174
2175 case IrOpcode::kCheckBounds: {
2176 Type* index_type = TypeOf(node->InputAt(0));
2177 Type* length_type = TypeOf(node->InputAt(1));
2178 if (index_type->Is(Type::Unsigned32())) {
2179 VisitBinop(node, UseInfo::TruncatingWord32(),
2180 MachineRepresentation::kWord32);
2181 if (lower() && index_type->Max() < length_type->Min()) {
2182 // The bounds check is redundant if we already know that
2183 // the index is within the bounds of [0.0, length[.
2184 DeferReplacement(node, node->InputAt(0));
2185 }
2186 } else {
2187 VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
2188 UseInfo::TruncatingWord32(),
2189 MachineRepresentation::kWord32);
2190 }
2191 return;
2192 }
2193 case IrOpcode::kCheckHeapObject: {
2194 if (InputCannotBe(node, Type::SignedSmall())) {
2195 VisitUnop(node, UseInfo::AnyTagged(),
2196 MachineRepresentation::kTaggedPointer);
2197 } else {
2198 VisitUnop(node, UseInfo::CheckedHeapObjectAsTaggedPointer(),
2199 MachineRepresentation::kTaggedPointer);
2200 }
2201 if (lower()) DeferReplacement(node, node->InputAt(0));
2202 return;
2203 }
2204 case IrOpcode::kCheckIf: {
2205 ProcessInput(node, 0, UseInfo::Bool());
2206 ProcessRemainingInputs(node, 1);
2207 SetOutput(node, MachineRepresentation::kNone);
2208 return;
2209 }
2210 case IrOpcode::kCheckNumber: {
2211 if (InputIs(node, Type::Number())) {
2212 if (truncation.IsUsedAsWord32()) {
2213 VisitUnop(node, UseInfo::TruncatingWord32(),
2214 MachineRepresentation::kWord32);
2215 } else {
2216 // TODO(jarin,bmeurer): We need to go to Tagged here, because
2217 // otherwise we cannot distinguish the hole NaN (which might need to
2218 // be treated as undefined). We should have a dedicated Type for
2219 // that at some point, and maybe even a dedicated truncation.
2220 VisitUnop(node, UseInfo::AnyTagged(),
2221 MachineRepresentation::kTagged);
2222 }
2223 if (lower()) DeferReplacement(node, node->InputAt(0));
2224 } else {
2225 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2226 }
2227 return;
2228 }
2229 case IrOpcode::kCheckSmi: {
2230 if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
2231 VisitUnop(node, UseInfo::CheckedSignedSmallAsWord32(),
2232 MachineRepresentation::kWord32);
2233 } else {
2234 VisitUnop(node, UseInfo::CheckedSignedSmallAsTaggedSigned(),
2235 MachineRepresentation::kTaggedSigned);
2236 }
2237 if (lower()) DeferReplacement(node, node->InputAt(0));
2238 return;
2239 }
2240 case IrOpcode::kCheckString: {
2241 if (InputIs(node, Type::String())) {
2242 VisitUnop(node, UseInfo::AnyTagged(),
2243 MachineRepresentation::kTaggedPointer);
2244 if (lower()) DeferReplacement(node, node->InputAt(0));
2245 } else {
2246 VisitUnop(node, UseInfo::AnyTagged(),
2247 MachineRepresentation::kTaggedPointer);
2248 }
2249 return;
2250 }
2251
2252 case IrOpcode::kAllocate: {
2253 ProcessInput(node, 0, UseInfo::TruncatingWord32());
2254 ProcessRemainingInputs(node, 1);
2255 SetOutput(node, MachineRepresentation::kTaggedPointer);
2256 return;
2257 }
2258 case IrOpcode::kLoadField: {
2259 if (truncation.IsUnused()) return VisitUnused(node);
2260 FieldAccess access = FieldAccessOf(node->op());
2261 MachineRepresentation const representation =
2262 access.machine_type.representation();
2263 VisitUnop(node, UseInfoForBasePointer(access), representation);
2264 return;
2265 }
2266 case IrOpcode::kStoreField: {
2267 FieldAccess access = FieldAccessOf(node->op());
2268 NodeInfo* input_info = GetInfo(node->InputAt(1));
2269 WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2270 access.base_is_tagged, access.machine_type.representation(),
2271 access.offset, access.type, input_info->representation(),
2272 node->InputAt(1));
2273 ProcessInput(node, 0, UseInfoForBasePointer(access));
2274 ProcessInput(node, 1, TruncatingUseInfoFromRepresentation(
2275 access.machine_type.representation()));
2276 ProcessRemainingInputs(node, 2);
2277 SetOutput(node, MachineRepresentation::kNone);
2278 if (lower()) {
2279 if (write_barrier_kind < access.write_barrier_kind) {
2280 access.write_barrier_kind = write_barrier_kind;
2281 NodeProperties::ChangeOp(
2282 node, jsgraph_->simplified()->StoreField(access));
2283 }
2284 }
2285 return;
2286 }
2287 case IrOpcode::kLoadBuffer: {
2288 if (truncation.IsUnused()) return VisitUnused(node);
2289 BufferAccess access = BufferAccessOf(node->op());
2290 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
2291 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
2292 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
2293 ProcessRemainingInputs(node, 3);
2294
2295 MachineRepresentation output;
2296 if (truncation.IdentifiesUndefinedAndNaNAndZero()) {
2297 if (truncation.IdentifiesNaNAndZero()) {
2298 // If undefined is truncated to a non-NaN number, we can use
2299 // the load's representation.
2300 output = access.machine_type().representation();
2301 } else {
2302 // If undefined is truncated to a number, but the use can
2303 // observe NaN, we need to output at least the float32
2304 // representation.
2305 if (access.machine_type().representation() ==
2306 MachineRepresentation::kFloat32) {
2307 output = access.machine_type().representation();
2308 } else {
2309 output = MachineRepresentation::kFloat64;
2310 }
2311 }
2312 } else {
2313 // If undefined is not truncated away, we need to have the tagged
2314 // representation.
2315 output = MachineRepresentation::kTagged;
2316 }
2317 SetOutput(node, output);
2318 if (lower()) lowering->DoLoadBuffer(node, output, changer_);
2319 return;
2320 }
2321 case IrOpcode::kStoreBuffer: {
2322 BufferAccess access = BufferAccessOf(node->op());
2323 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer
2324 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset
2325 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length
2326 ProcessInput(node, 3,
2327 TruncatingUseInfoFromRepresentation(
2328 access.machine_type().representation())); // value
2329 ProcessRemainingInputs(node, 4);
2330 SetOutput(node, MachineRepresentation::kNone);
2331 if (lower()) lowering->DoStoreBuffer(node);
2332 return;
2333 }
2334 case IrOpcode::kLoadElement: {
2335 if (truncation.IsUnused()) return VisitUnused(node);
2336 ElementAccess access = ElementAccessOf(node->op());
2337 VisitBinop(node, UseInfoForBasePointer(access),
2338 UseInfo::TruncatingWord32(),
2339 access.machine_type.representation());
2340 return;
2341 }
2342 case IrOpcode::kStoreElement: {
2343 ElementAccess access = ElementAccessOf(node->op());
2344 NodeInfo* input_info = GetInfo(node->InputAt(2));
2345 WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
2346 access.base_is_tagged, access.machine_type.representation(),
2347 access.type, input_info->representation(), node->InputAt(2));
2348 ProcessInput(node, 0, UseInfoForBasePointer(access)); // base
2349 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index
2350 ProcessInput(node, 2,
2351 TruncatingUseInfoFromRepresentation(
2352 access.machine_type.representation())); // value
2353 ProcessRemainingInputs(node, 3);
2354 SetOutput(node, MachineRepresentation::kNone);
2355 if (lower()) {
2356 if (write_barrier_kind < access.write_barrier_kind) {
2357 access.write_barrier_kind = write_barrier_kind;
2358 NodeProperties::ChangeOp(
2359 node, jsgraph_->simplified()->StoreElement(access));
2360 }
2361 }
2362 return;
2363 }
2364 case IrOpcode::kLoadTypedElement: {
2365 MachineRepresentation const rep =
2366 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2367 ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2368 ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2369 ProcessInput(node, 2, UseInfo::PointerInt()); // external pointer
2370 ProcessInput(node, 3, UseInfo::TruncatingWord32()); // index
2371 ProcessRemainingInputs(node, 4);
2372 SetOutput(node, rep);
2373 return;
2374 }
2375 case IrOpcode::kStoreTypedElement: {
2376 MachineRepresentation const rep =
2377 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
2378 ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
2379 ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
2380 ProcessInput(node, 2, UseInfo::PointerInt()); // external pointer
2381 ProcessInput(node, 3, UseInfo::TruncatingWord32()); // index
2382 ProcessInput(node, 4,
2383 TruncatingUseInfoFromRepresentation(rep)); // value
2384 ProcessRemainingInputs(node, 5);
2385 SetOutput(node, MachineRepresentation::kNone);
2386 return;
2387 }
2388 case IrOpcode::kPlainPrimitiveToNumber: {
2389 if (InputIs(node, Type::Boolean())) {
2390 VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32);
2391 if (lower()) DeferReplacement(node, node->InputAt(0));
2392 } else if (InputIs(node, Type::String())) {
2393 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2394 if (lower()) lowering->DoStringToNumber(node);
2395 } else if (truncation.IsUsedAsWord32()) {
2396 if (InputIs(node, Type::NumberOrOddball())) {
2397 VisitUnop(node, UseInfo::TruncatingWord32(),
2398 MachineRepresentation::kWord32);
2399 if (lower()) DeferReplacement(node, node->InputAt(0));
2400 } else {
2401 VisitUnop(node, UseInfo::AnyTagged(),
2402 MachineRepresentation::kWord32);
2403 if (lower()) {
2404 NodeProperties::ChangeOp(node,
2405 simplified()->PlainPrimitiveToWord32());
2406 }
2407 }
2408 } else if (truncation.IsUsedAsFloat64()) {
2409 if (InputIs(node, Type::NumberOrOddball())) {
2410 VisitUnop(node, UseInfo::TruncatingFloat64(),
2411 MachineRepresentation::kFloat64);
2412 if (lower()) DeferReplacement(node, node->InputAt(0));
2413 } else {
2414 VisitUnop(node, UseInfo::AnyTagged(),
2415 MachineRepresentation::kFloat64);
2416 if (lower()) {
2417 NodeProperties::ChangeOp(node,
2418 simplified()->PlainPrimitiveToFloat64());
2419 }
2420 }
2421 } else {
2422 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2423 }
2424 return;
2425 }
2426 case IrOpcode::kObjectIsCallable: {
2427 // TODO(turbofan): Add Type::Callable to optimize this?
2428 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2429 return;
2430 }
2431 case IrOpcode::kObjectIsNumber: {
2432 VisitObjectIs(node, Type::Number(), lowering);
2433 return;
2434 }
2435 case IrOpcode::kObjectIsReceiver: {
2436 VisitObjectIs(node, Type::Receiver(), lowering);
2437 return;
2438 }
2439 case IrOpcode::kObjectIsSmi: {
2440 // TODO(turbofan): Optimize based on input representation.
2441 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2442 return;
2443 }
2444 case IrOpcode::kObjectIsString: {
2445 VisitObjectIs(node, Type::String(), lowering);
2446 return;
2447 }
2448 case IrOpcode::kObjectIsUndetectable: {
2449 VisitObjectIs(node, Type::Undetectable(), lowering);
2450 return;
2451 }
2452 case IrOpcode::kArrayBufferWasNeutered: {
2453 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2454 return;
2455 }
2456 case IrOpcode::kCheckFloat64Hole: {
2457 if (truncation.IsUnused()) return VisitUnused(node);
2458 CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op());
2459 ProcessInput(node, 0, UseInfo::TruncatingFloat64());
2460 ProcessRemainingInputs(node, 1);
2461 SetOutput(node, MachineRepresentation::kFloat64);
2462 if (truncation.IsUsedAsFloat64() &&
2463 mode == CheckFloat64HoleMode::kAllowReturnHole) {
2464 if (lower()) DeferReplacement(node, node->InputAt(0));
2465 }
2466 return;
2467 }
2468 case IrOpcode::kCheckTaggedHole: {
2469 VisitUnop(node, UseInfo::AnyTagged(),
2470 MachineRepresentation::kTaggedPointer);
2471 return;
2472 }
2473 case IrOpcode::kConvertTaggedHoleToUndefined: {
2474 if (InputIs(node, Type::NumberOrOddball()) &&
2475 truncation.IsUsedAsWord32()) {
2476 // Propagate the Word32 truncation.
2477 VisitUnop(node, UseInfo::TruncatingWord32(),
2478 MachineRepresentation::kWord32);
2479 if (lower()) DeferReplacement(node, node->InputAt(0));
2480 } else if (InputIs(node, Type::NumberOrOddball()) &&
2481 truncation.IsUsedAsFloat64()) {
2482 // Propagate the Float64 truncation.
2483 VisitUnop(node, UseInfo::TruncatingFloat64(),
2484 MachineRepresentation::kFloat64);
2485 if (lower()) DeferReplacement(node, node->InputAt(0));
2486 } else if (InputIs(node, Type::NonInternal())) {
2487 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2488 if (lower()) DeferReplacement(node, node->InputAt(0));
2489 } else {
2490 // TODO(turbofan): Add a (Tagged) truncation that identifies hole
2491 // and undefined, i.e. for a[i] === obj cases.
2492 VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
2493 }
2494 return;
2495 }
2496 case IrOpcode::kCheckMaps:
2497 case IrOpcode::kTransitionElementsKind: {
2498 VisitInputs(node);
2499 return SetOutput(node, MachineRepresentation::kNone);
2500 }
2501 case IrOpcode::kEnsureWritableFastElements:
2502 return VisitBinop(node, UseInfo::AnyTagged(),
2503 MachineRepresentation::kTaggedPointer);
2504 case IrOpcode::kMaybeGrowFastElements: {
2505 ProcessInput(node, 0, UseInfo::AnyTagged()); // object
2506 ProcessInput(node, 1, UseInfo::AnyTagged()); // elements
2507 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // index
2508 ProcessInput(node, 3, UseInfo::TruncatingWord32()); // length
2509 ProcessRemainingInputs(node, 4);
2510 SetOutput(node, MachineRepresentation::kTaggedPointer);
2511 return;
2512 }
2513
2514 case IrOpcode::kNumberSilenceNaN:
2515 VisitUnop(node, UseInfo::TruncatingFloat64(),
2516 MachineRepresentation::kFloat64);
2517 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
2518 return;
2519 case IrOpcode::kStateValues:
2520 return VisitStateValues(node);
2521 case IrOpcode::kObjectState:
2522 return VisitObjectState(node);
2523 case IrOpcode::kTypeGuard: {
2524 // We just get rid of the sigma here. In principle, it should be
2525 // possible to refine the truncation and representation based on
2526 // the sigma's type.
2527 MachineRepresentation output =
2528 GetOutputInfoForPhi(node, TypeOf(node->InputAt(0)), truncation);
2529 VisitUnop(node, UseInfo(output, truncation), output);
2530 if (lower()) DeferReplacement(node, node->InputAt(0));
2531 return;
2532 }
2533
2534 case IrOpcode::kOsrGuard:
2535 return VisitOsrGuard(node);
2536
2537 case IrOpcode::kFinishRegion:
2538 VisitInputs(node);
2539 // Assume the output is tagged pointer.
2540 return SetOutput(node, MachineRepresentation::kTaggedPointer);
2541
2542 case IrOpcode::kReturn:
2543 VisitReturn(node);
2544 // Assume the output is tagged.
2545 return SetOutput(node, MachineRepresentation::kTagged);
2546
2547 // Operators with all inputs tagged and no or tagged output have uniform
2548 // handling.
2549 case IrOpcode::kEnd:
2550 case IrOpcode::kIfSuccess:
2551 case IrOpcode::kIfException:
2552 case IrOpcode::kIfTrue:
2553 case IrOpcode::kIfFalse:
2554 case IrOpcode::kDeoptimize:
2555 case IrOpcode::kEffectPhi:
2556 case IrOpcode::kTerminate:
2557 case IrOpcode::kFrameState:
2558 case IrOpcode::kCheckpoint:
2559 case IrOpcode::kLoop:
2560 case IrOpcode::kMerge:
2561 case IrOpcode::kThrow:
2562 case IrOpcode::kBeginRegion:
2563 case IrOpcode::kProjection:
2564 case IrOpcode::kOsrValue:
2565 // All JavaScript operators except JSToNumber have uniform handling.
2566 #define OPCODE_CASE(name) case IrOpcode::k##name:
2567 JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
2568 JS_OTHER_UNOP_LIST(OPCODE_CASE)
2569 JS_OBJECT_OP_LIST(OPCODE_CASE)
2570 JS_CONTEXT_OP_LIST(OPCODE_CASE)
2571 JS_OTHER_OP_LIST(OPCODE_CASE)
2572 #undef OPCODE_CASE
2573 case IrOpcode::kJSToInteger:
2574 case IrOpcode::kJSToLength:
2575 case IrOpcode::kJSToName:
2576 case IrOpcode::kJSToObject:
2577 case IrOpcode::kJSToString:
2578 VisitInputs(node);
2579 // Assume the output is tagged.
2580 return SetOutput(node, MachineRepresentation::kTagged);
2581
2582 default:
2583 V8_Fatal(
2584 __FILE__, __LINE__,
2585 "Representation inference: unsupported opcode %i (%s), node #%i\n.",
2586 node->opcode(), node->op()->mnemonic(), node->id());
2587 break;
2588 }
2589 UNREACHABLE();
2590 }
2591
DeferReplacement(Node * node,Node * replacement)2592 void DeferReplacement(Node* node, Node* replacement) {
2593 TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
2594 node->op()->mnemonic(), replacement->id(),
2595 replacement->op()->mnemonic());
2596
2597 // Disconnect the node from effect and control chains, if necessary.
2598 if (node->op()->EffectInputCount() > 0) {
2599 DCHECK_LT(0, node->op()->ControlInputCount());
2600 // Disconnect the node from effect and control chains.
2601 Node* control = NodeProperties::GetControlInput(node);
2602 Node* effect = NodeProperties::GetEffectInput(node);
2603 ReplaceEffectControlUses(node, effect, control);
2604 }
2605
2606 replacements_.push_back(node);
2607 replacements_.push_back(replacement);
2608
2609 node->NullAllInputs(); // Node is now dead.
2610 }
2611
Kill(Node * node)2612 void Kill(Node* node) {
2613 TRACE("killing #%d:%s\n", node->id(), node->op()->mnemonic());
2614
2615 if (node->op()->EffectInputCount() == 1) {
2616 DCHECK_LT(0, node->op()->ControlInputCount());
2617 // Disconnect the node from effect and control chains.
2618 Node* control = NodeProperties::GetControlInput(node);
2619 Node* effect = NodeProperties::GetEffectInput(node);
2620 ReplaceEffectControlUses(node, effect, control);
2621 } else {
2622 DCHECK_EQ(0, node->op()->EffectInputCount());
2623 DCHECK_EQ(0, node->op()->ControlOutputCount());
2624 DCHECK_EQ(0, node->op()->EffectOutputCount());
2625 }
2626
2627 node->ReplaceUses(jsgraph_->Dead());
2628
2629 node->NullAllInputs(); // The {node} is now dead.
2630 }
2631
PrintOutputInfo(NodeInfo * info)2632 void PrintOutputInfo(NodeInfo* info) {
2633 if (FLAG_trace_representation) {
2634 OFStream os(stdout);
2635 os << info->representation();
2636 }
2637 }
2638
PrintRepresentation(MachineRepresentation rep)2639 void PrintRepresentation(MachineRepresentation rep) {
2640 if (FLAG_trace_representation) {
2641 OFStream os(stdout);
2642 os << rep;
2643 }
2644 }
2645
PrintTruncation(Truncation truncation)2646 void PrintTruncation(Truncation truncation) {
2647 if (FLAG_trace_representation) {
2648 OFStream os(stdout);
2649 os << truncation.description() << std::endl;
2650 }
2651 }
2652
PrintUseInfo(UseInfo info)2653 void PrintUseInfo(UseInfo info) {
2654 if (FLAG_trace_representation) {
2655 OFStream os(stdout);
2656 os << info.representation() << ":" << info.truncation().description();
2657 }
2658 }
2659
2660 private:
2661 JSGraph* jsgraph_;
2662 Zone* zone_; // Temporary zone.
2663 size_t const count_; // number of nodes in the graph
2664 ZoneVector<NodeInfo> info_; // node id -> usage information
2665 #ifdef DEBUG
2666 ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
2667 // requirements on inputs.
2668 #endif // DEBUG
2669 NodeVector nodes_; // collected nodes
2670 NodeVector replacements_; // replacements to be done after lowering
2671 Phase phase_; // current phase of algorithm
2672 RepresentationChanger* changer_; // for inserting representation changes
2673 ZoneQueue<Node*> queue_; // queue for traversing the graph
2674
2675 struct NodeState {
2676 Node* node;
2677 int input_index;
2678 };
2679 ZoneStack<NodeState> typing_stack_; // stack for graph typing.
2680 // TODO(danno): RepresentationSelector shouldn't know anything about the
2681 // source positions table, but must for now since there currently is no other
2682 // way to pass down source position information to nodes created during
2683 // lowering. Once this phase becomes a vanilla reducer, it should get source
2684 // position information via the SourcePositionWrapper like all other reducers.
2685 SourcePositionTable* source_positions_;
2686 TypeCache const& type_cache_;
2687 OperationTyper op_typer_; // helper for the feedback typer
2688
GetInfo(Node * node)2689 NodeInfo* GetInfo(Node* node) {
2690 DCHECK(node->id() < count_);
2691 return &info_[node->id()];
2692 }
zone()2693 Zone* zone() { return zone_; }
graph_zone()2694 Zone* graph_zone() { return jsgraph_->zone(); }
2695 };
2696
SimplifiedLowering(JSGraph * jsgraph,Zone * zone,SourcePositionTable * source_positions)2697 SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone,
2698 SourcePositionTable* source_positions)
2699 : jsgraph_(jsgraph),
2700 zone_(zone),
2701 type_cache_(TypeCache::Get()),
2702 source_positions_(source_positions) {}
2703
LowerAllNodes()2704 void SimplifiedLowering::LowerAllNodes() {
2705 RepresentationChanger changer(jsgraph(), jsgraph()->isolate());
2706 RepresentationSelector selector(jsgraph(), zone_, &changer,
2707 source_positions_);
2708 selector.Run(this);
2709 }
2710
DoJSToNumberTruncatesToFloat64(Node * node,RepresentationSelector * selector)2711 void SimplifiedLowering::DoJSToNumberTruncatesToFloat64(
2712 Node* node, RepresentationSelector* selector) {
2713 DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode());
2714 Node* value = node->InputAt(0);
2715 Node* context = node->InputAt(1);
2716 Node* frame_state = node->InputAt(2);
2717 Node* effect = node->InputAt(3);
2718 Node* control = node->InputAt(4);
2719 Node* throwing;
2720
2721 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2722 Node* branch0 =
2723 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2724
2725 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2726 Node* etrue0 = effect;
2727 Node* vtrue0;
2728 {
2729 vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
2730 vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
2731 }
2732
2733 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2734 Node* efalse0 = effect;
2735 Node* vfalse0;
2736 {
2737 throwing = vfalse0 = efalse0 =
2738 graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context,
2739 frame_state, efalse0, if_false0);
2740 if_false0 = graph()->NewNode(common()->IfSuccess(), throwing);
2741
2742 Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
2743 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
2744
2745 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2746 Node* etrue1 = efalse0;
2747 Node* vtrue1;
2748 {
2749 vtrue1 =
2750 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
2751 vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
2752 }
2753
2754 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2755 Node* efalse1 = efalse0;
2756 Node* vfalse1;
2757 {
2758 vfalse1 = efalse1 = graph()->NewNode(
2759 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
2760 efalse1, if_false1);
2761 }
2762
2763 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2764 efalse0 =
2765 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
2766 vfalse0 =
2767 graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
2768 vtrue1, vfalse1, if_false0);
2769 }
2770
2771 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2772 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2773 value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
2774 vtrue0, vfalse0, control);
2775
2776 // Replace effect and control uses appropriately.
2777 for (Edge edge : node->use_edges()) {
2778 if (NodeProperties::IsControlEdge(edge)) {
2779 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
2780 edge.from()->ReplaceUses(control);
2781 edge.from()->Kill();
2782 } else if (edge.from()->opcode() == IrOpcode::kIfException) {
2783 edge.UpdateTo(throwing);
2784 } else {
2785 UNREACHABLE();
2786 }
2787 } else if (NodeProperties::IsEffectEdge(edge)) {
2788 edge.UpdateTo(effect);
2789 }
2790 }
2791
2792 selector->DeferReplacement(node, value);
2793 }
2794
DoJSToNumberTruncatesToWord32(Node * node,RepresentationSelector * selector)2795 void SimplifiedLowering::DoJSToNumberTruncatesToWord32(
2796 Node* node, RepresentationSelector* selector) {
2797 DCHECK_EQ(IrOpcode::kJSToNumber, node->opcode());
2798 Node* value = node->InputAt(0);
2799 Node* context = node->InputAt(1);
2800 Node* frame_state = node->InputAt(2);
2801 Node* effect = node->InputAt(3);
2802 Node* control = node->InputAt(4);
2803 Node* throwing;
2804
2805 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2806 Node* branch0 =
2807 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2808
2809 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2810 Node* etrue0 = effect;
2811 Node* vtrue0 =
2812 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
2813
2814 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2815 Node* efalse0 = effect;
2816 Node* vfalse0;
2817 {
2818 throwing = vfalse0 = efalse0 =
2819 graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context,
2820 frame_state, efalse0, if_false0);
2821 if_false0 = graph()->NewNode(common()->IfSuccess(), throwing);
2822
2823 Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
2824 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
2825
2826 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
2827 Node* etrue1 = efalse0;
2828 Node* vtrue1 =
2829 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
2830
2831 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
2832 Node* efalse1 = efalse0;
2833 Node* vfalse1;
2834 {
2835 vfalse1 = efalse1 = graph()->NewNode(
2836 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
2837 efalse1, if_false1);
2838 vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
2839 }
2840
2841 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
2842 efalse0 =
2843 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
2844 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2845 vtrue1, vfalse1, if_false0);
2846 }
2847
2848 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2849 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2850 value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
2851 vtrue0, vfalse0, control);
2852
2853 // Replace effect and control uses appropriately.
2854 for (Edge edge : node->use_edges()) {
2855 if (NodeProperties::IsControlEdge(edge)) {
2856 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
2857 edge.from()->ReplaceUses(control);
2858 edge.from()->Kill();
2859 } else if (edge.from()->opcode() == IrOpcode::kIfException) {
2860 edge.UpdateTo(throwing);
2861 } else {
2862 UNREACHABLE();
2863 }
2864 } else if (NodeProperties::IsEffectEdge(edge)) {
2865 edge.UpdateTo(effect);
2866 }
2867 }
2868
2869 selector->DeferReplacement(node, value);
2870 }
2871
DoLoadBuffer(Node * node,MachineRepresentation output_rep,RepresentationChanger * changer)2872 void SimplifiedLowering::DoLoadBuffer(Node* node,
2873 MachineRepresentation output_rep,
2874 RepresentationChanger* changer) {
2875 DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode());
2876 DCHECK_NE(MachineRepresentation::kNone, output_rep);
2877 MachineType const access_type = BufferAccessOf(node->op()).machine_type();
2878 if (output_rep != access_type.representation()) {
2879 Node* const buffer = node->InputAt(0);
2880 Node* const offset = node->InputAt(1);
2881 Node* const length = node->InputAt(2);
2882 Node* const effect = node->InputAt(3);
2883 Node* const control = node->InputAt(4);
2884 Node* const index =
2885 machine()->Is64()
2886 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset)
2887 : offset;
2888
2889 Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
2890 Node* branch =
2891 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
2892
2893 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2894 Node* etrue = graph()->NewNode(machine()->Load(access_type), buffer, index,
2895 effect, if_true);
2896 Type* element_type =
2897 Type::Intersect(NodeProperties::GetType(node), Type::Number(), zone());
2898 Node* vtrue = changer->GetRepresentationFor(
2899 etrue, access_type.representation(), element_type, node,
2900 UseInfo(output_rep, Truncation::None()));
2901
2902 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2903 Node* efalse = effect;
2904 Node* vfalse;
2905 if (output_rep == MachineRepresentation::kTagged) {
2906 vfalse = jsgraph()->UndefinedConstant();
2907 } else if (output_rep == MachineRepresentation::kFloat64) {
2908 vfalse =
2909 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
2910 } else if (output_rep == MachineRepresentation::kFloat32) {
2911 vfalse =
2912 jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
2913 } else {
2914 vfalse = jsgraph()->Int32Constant(0);
2915 }
2916
2917 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
2918 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
2919
2920 // Replace effect uses of {node} with the {ephi}.
2921 NodeProperties::ReplaceUses(node, node, ephi);
2922
2923 // Turn the {node} into a Phi.
2924 node->ReplaceInput(0, vtrue);
2925 node->ReplaceInput(1, vfalse);
2926 node->ReplaceInput(2, merge);
2927 node->TrimInputCount(3);
2928 NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2));
2929 } else {
2930 NodeProperties::ChangeOp(node, machine()->CheckedLoad(access_type));
2931 }
2932 }
2933
2934
DoStoreBuffer(Node * node)2935 void SimplifiedLowering::DoStoreBuffer(Node* node) {
2936 DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode());
2937 MachineRepresentation const rep =
2938 BufferAccessOf(node->op()).machine_type().representation();
2939 NodeProperties::ChangeOp(node, machine()->CheckedStore(rep));
2940 }
2941
Float64Round(Node * const node)2942 Node* SimplifiedLowering::Float64Round(Node* const node) {
2943 Node* const one = jsgraph()->Float64Constant(1.0);
2944 Node* const one_half = jsgraph()->Float64Constant(0.5);
2945 Node* const input = node->InputAt(0);
2946
2947 // Round up towards Infinity, and adjust if the difference exceeds 0.5.
2948 Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
2949 node->InputAt(0));
2950 return graph()->NewNode(
2951 common()->Select(MachineRepresentation::kFloat64),
2952 graph()->NewNode(
2953 machine()->Float64LessThanOrEqual(),
2954 graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
2955 result, graph()->NewNode(machine()->Float64Sub(), result, one));
2956 }
2957
Float64Sign(Node * const node)2958 Node* SimplifiedLowering::Float64Sign(Node* const node) {
2959 Node* const minus_one = jsgraph()->Float64Constant(-1.0);
2960 Node* const zero = jsgraph()->Float64Constant(0.0);
2961 Node* const one = jsgraph()->Float64Constant(1.0);
2962
2963 Node* const input = node->InputAt(0);
2964
2965 return graph()->NewNode(
2966 common()->Select(MachineRepresentation::kFloat64),
2967 graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
2968 graph()->NewNode(
2969 common()->Select(MachineRepresentation::kFloat64),
2970 graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
2971 input));
2972 }
2973
Int32Abs(Node * const node)2974 Node* SimplifiedLowering::Int32Abs(Node* const node) {
2975 Node* const input = node->InputAt(0);
2976
2977 // Generate case for absolute integer value.
2978 //
2979 // let sign = input >> 31 in
2980 // (input ^ sign) - sign
2981
2982 Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
2983 jsgraph()->Int32Constant(31));
2984 return graph()->NewNode(machine()->Int32Sub(),
2985 graph()->NewNode(machine()->Word32Xor(), input, sign),
2986 sign);
2987 }
2988
Int32Div(Node * const node)2989 Node* SimplifiedLowering::Int32Div(Node* const node) {
2990 Int32BinopMatcher m(node);
2991 Node* const zero = jsgraph()->Int32Constant(0);
2992 Node* const minus_one = jsgraph()->Int32Constant(-1);
2993 Node* const lhs = m.left().node();
2994 Node* const rhs = m.right().node();
2995
2996 if (m.right().Is(-1)) {
2997 return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
2998 } else if (m.right().Is(0)) {
2999 return rhs;
3000 } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) {
3001 return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
3002 }
3003
3004 // General case for signed integer division.
3005 //
3006 // if 0 < rhs then
3007 // lhs / rhs
3008 // else
3009 // if rhs < -1 then
3010 // lhs / rhs
3011 // else if rhs == 0 then
3012 // 0
3013 // else
3014 // 0 - lhs
3015 //
3016 // Note: We do not use the Diamond helper class here, because it really hurts
3017 // readability with nested diamonds.
3018 const Operator* const merge_op = common()->Merge(2);
3019 const Operator* const phi_op =
3020 common()->Phi(MachineRepresentation::kWord32, 2);
3021
3022 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3023 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3024 graph()->start());
3025
3026 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3027 Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
3028
3029 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3030 Node* false0;
3031 {
3032 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3033 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
3034
3035 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3036 Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
3037
3038 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3039 Node* false1;
3040 {
3041 Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3042 Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
3043
3044 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3045 Node* true2 = zero;
3046
3047 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3048 Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
3049
3050 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3051 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3052 }
3053
3054 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3055 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3056 }
3057
3058 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3059 return graph()->NewNode(phi_op, true0, false0, merge0);
3060 }
3061
3062
Int32Mod(Node * const node)3063 Node* SimplifiedLowering::Int32Mod(Node* const node) {
3064 Int32BinopMatcher m(node);
3065 Node* const zero = jsgraph()->Int32Constant(0);
3066 Node* const minus_one = jsgraph()->Int32Constant(-1);
3067 Node* const lhs = m.left().node();
3068 Node* const rhs = m.right().node();
3069
3070 if (m.right().Is(-1) || m.right().Is(0)) {
3071 return zero;
3072 } else if (m.right().HasValue()) {
3073 return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
3074 }
3075
3076 // General case for signed integer modulus, with optimization for (unknown)
3077 // power of 2 right hand side.
3078 //
3079 // if 0 < rhs then
3080 // msk = rhs - 1
3081 // if rhs & msk != 0 then
3082 // lhs % rhs
3083 // else
3084 // if lhs < 0 then
3085 // -(-lhs & msk)
3086 // else
3087 // lhs & msk
3088 // else
3089 // if rhs < -1 then
3090 // lhs % rhs
3091 // else
3092 // zero
3093 //
3094 // Note: We do not use the Diamond helper class here, because it really hurts
3095 // readability with nested diamonds.
3096 const Operator* const merge_op = common()->Merge(2);
3097 const Operator* const phi_op =
3098 common()->Phi(MachineRepresentation::kWord32, 2);
3099
3100 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
3101 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
3102 graph()->start());
3103
3104 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3105 Node* true0;
3106 {
3107 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3108
3109 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3110 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
3111
3112 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3113 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3114
3115 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3116 Node* false1;
3117 {
3118 Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
3119 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
3120 check2, if_false1);
3121
3122 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
3123 Node* true2 = graph()->NewNode(
3124 machine()->Int32Sub(), zero,
3125 graph()->NewNode(machine()->Word32And(),
3126 graph()->NewNode(machine()->Int32Sub(), zero, lhs),
3127 msk));
3128
3129 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
3130 Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
3131
3132 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
3133 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
3134 }
3135
3136 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
3137 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
3138 }
3139
3140 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3141 Node* false0;
3142 {
3143 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
3144 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
3145 check1, if_false0);
3146
3147 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3148 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
3149
3150 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3151 Node* false1 = zero;
3152
3153 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
3154 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
3155 }
3156
3157 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3158 return graph()->NewNode(phi_op, true0, false0, merge0);
3159 }
3160
Int32Sign(Node * const node)3161 Node* SimplifiedLowering::Int32Sign(Node* const node) {
3162 Node* const minus_one = jsgraph()->Int32Constant(-1);
3163 Node* const zero = jsgraph()->Int32Constant(0);
3164 Node* const one = jsgraph()->Int32Constant(1);
3165
3166 Node* const input = node->InputAt(0);
3167
3168 return graph()->NewNode(
3169 common()->Select(MachineRepresentation::kWord32),
3170 graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
3171 graph()->NewNode(
3172 common()->Select(MachineRepresentation::kWord32),
3173 graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
3174 zero));
3175 }
3176
Uint32Div(Node * const node)3177 Node* SimplifiedLowering::Uint32Div(Node* const node) {
3178 Uint32BinopMatcher m(node);
3179 Node* const zero = jsgraph()->Uint32Constant(0);
3180 Node* const lhs = m.left().node();
3181 Node* const rhs = m.right().node();
3182
3183 if (m.right().Is(0)) {
3184 return zero;
3185 } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) {
3186 return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
3187 }
3188
3189 Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
3190 Diamond d(graph(), common(), check, BranchHint::kFalse);
3191 Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
3192 return d.Phi(MachineRepresentation::kWord32, zero, div);
3193 }
3194
3195
Uint32Mod(Node * const node)3196 Node* SimplifiedLowering::Uint32Mod(Node* const node) {
3197 Uint32BinopMatcher m(node);
3198 Node* const minus_one = jsgraph()->Int32Constant(-1);
3199 Node* const zero = jsgraph()->Uint32Constant(0);
3200 Node* const lhs = m.left().node();
3201 Node* const rhs = m.right().node();
3202
3203 if (m.right().Is(0)) {
3204 return zero;
3205 } else if (m.right().HasValue()) {
3206 return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
3207 }
3208
3209 // General case for unsigned integer modulus, with optimization for (unknown)
3210 // power of 2 right hand side.
3211 //
3212 // if rhs then
3213 // msk = rhs - 1
3214 // if rhs & msk != 0 then
3215 // lhs % rhs
3216 // else
3217 // lhs & msk
3218 // else
3219 // zero
3220 //
3221 // Note: We do not use the Diamond helper class here, because it really hurts
3222 // readability with nested diamonds.
3223 const Operator* const merge_op = common()->Merge(2);
3224 const Operator* const phi_op =
3225 common()->Phi(MachineRepresentation::kWord32, 2);
3226
3227 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs,
3228 graph()->start());
3229
3230 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
3231 Node* true0;
3232 {
3233 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
3234
3235 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
3236 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
3237
3238 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
3239 Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
3240
3241 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
3242 Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
3243
3244 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
3245 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
3246 }
3247
3248 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
3249 Node* false0 = zero;
3250
3251 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
3252 return graph()->NewNode(phi_op, true0, false0, merge0);
3253 }
3254
DoMax(Node * node,Operator const * op,MachineRepresentation rep)3255 void SimplifiedLowering::DoMax(Node* node, Operator const* op,
3256 MachineRepresentation rep) {
3257 Node* const lhs = node->InputAt(0);
3258 Node* const rhs = node->InputAt(1);
3259
3260 node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
3261 DCHECK_EQ(rhs, node->InputAt(1));
3262 node->AppendInput(graph()->zone(), lhs);
3263 NodeProperties::ChangeOp(node, common()->Select(rep));
3264 }
3265
DoMin(Node * node,Operator const * op,MachineRepresentation rep)3266 void SimplifiedLowering::DoMin(Node* node, Operator const* op,
3267 MachineRepresentation rep) {
3268 Node* const lhs = node->InputAt(0);
3269 Node* const rhs = node->InputAt(1);
3270
3271 node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
3272 DCHECK_EQ(lhs, node->InputAt(1));
3273 DCHECK_EQ(rhs, node->InputAt(2));
3274 NodeProperties::ChangeOp(node, common()->Select(rep));
3275 }
3276
DoShift(Node * node,Operator const * op,Type * rhs_type)3277 void SimplifiedLowering::DoShift(Node* node, Operator const* op,
3278 Type* rhs_type) {
3279 Node* const rhs = NodeProperties::GetValueInput(node, 1);
3280 if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) {
3281 node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
3282 jsgraph()->Int32Constant(0x1f)));
3283 }
3284 DCHECK(op->HasProperty(Operator::kPure));
3285 ChangeToPureOp(node, op);
3286 }
3287
DoStringToNumber(Node * node)3288 void SimplifiedLowering::DoStringToNumber(Node* node) {
3289 Operator::Properties properties = Operator::kEliminatable;
3290 Callable callable = CodeFactory::StringToNumber(isolate());
3291 CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
3292 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
3293 isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
3294 node->InsertInput(graph()->zone(), 0,
3295 jsgraph()->HeapConstant(callable.code()));
3296 node->AppendInput(graph()->zone(), jsgraph()->NoContextConstant());
3297 node->AppendInput(graph()->zone(), graph()->start());
3298 NodeProperties::ChangeOp(node, common()->Call(desc));
3299 }
3300
DoIntegral32ToBit(Node * node)3301 void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
3302 Node* const input = node->InputAt(0);
3303 Node* const zero = jsgraph()->Int32Constant(0);
3304 Operator const* const op = machine()->Word32Equal();
3305
3306 node->ReplaceInput(0, graph()->NewNode(op, input, zero));
3307 node->AppendInput(graph()->zone(), zero);
3308 NodeProperties::ChangeOp(node, op);
3309 }
3310
DoOrderedNumberToBit(Node * node)3311 void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
3312 Node* const input = node->InputAt(0);
3313
3314 node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
3315 jsgraph()->Float64Constant(0.0)));
3316 node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
3317 NodeProperties::ChangeOp(node, machine()->Word32Equal());
3318 }
3319
DoNumberToBit(Node * node)3320 void SimplifiedLowering::DoNumberToBit(Node* node) {
3321 Node* const input = node->InputAt(0);
3322
3323 node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
3324 node->AppendInput(graph()->zone(),
3325 graph()->NewNode(machine()->Float64Abs(), input));
3326 NodeProperties::ChangeOp(node, machine()->Float64LessThan());
3327 }
3328
DoIntegerToUint8Clamped(Node * node)3329 void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
3330 Node* const input = node->InputAt(0);
3331 Node* const min = jsgraph()->Float64Constant(0.0);
3332 Node* const max = jsgraph()->Float64Constant(255.0);
3333
3334 node->ReplaceInput(
3335 0, graph()->NewNode(machine()->Float64LessThan(), min, input));
3336 node->AppendInput(
3337 graph()->zone(),
3338 graph()->NewNode(
3339 common()->Select(MachineRepresentation::kFloat64),
3340 graph()->NewNode(machine()->Float64LessThan(), input, max), input,
3341 max));
3342 node->AppendInput(graph()->zone(), min);
3343 NodeProperties::ChangeOp(node,
3344 common()->Select(MachineRepresentation::kFloat64));
3345 }
3346
DoNumberToUint8Clamped(Node * node)3347 void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
3348 Node* const input = node->InputAt(0);
3349 Node* const min = jsgraph()->Float64Constant(0.0);
3350 Node* const max = jsgraph()->Float64Constant(255.0);
3351
3352 node->ReplaceInput(
3353 0, graph()->NewNode(
3354 common()->Select(MachineRepresentation::kFloat64),
3355 graph()->NewNode(machine()->Float64LessThan(), min, input),
3356 graph()->NewNode(
3357 common()->Select(MachineRepresentation::kFloat64),
3358 graph()->NewNode(machine()->Float64LessThan(), input, max),
3359 input, max),
3360 min));
3361 NodeProperties::ChangeOp(node,
3362 machine()->Float64RoundTiesEven().placeholder());
3363 }
3364
DoSigned32ToUint8Clamped(Node * node)3365 void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
3366 Node* const input = node->InputAt(0);
3367 Node* const min = jsgraph()->Int32Constant(0);
3368 Node* const max = jsgraph()->Int32Constant(255);
3369
3370 node->ReplaceInput(
3371 0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
3372 node->AppendInput(
3373 graph()->zone(),
3374 graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
3375 graph()->NewNode(machine()->Int32LessThan(), input, min),
3376 min, input));
3377 node->AppendInput(graph()->zone(), max);
3378 NodeProperties::ChangeOp(node,
3379 common()->Select(MachineRepresentation::kWord32));
3380 }
3381
DoUnsigned32ToUint8Clamped(Node * node)3382 void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
3383 Node* const input = node->InputAt(0);
3384 Node* const max = jsgraph()->Uint32Constant(255u);
3385
3386 node->ReplaceInput(
3387 0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
3388 node->AppendInput(graph()->zone(), input);
3389 node->AppendInput(graph()->zone(), max);
3390 NodeProperties::ChangeOp(node,
3391 common()->Select(MachineRepresentation::kWord32));
3392 }
3393
ToNumberCode()3394 Node* SimplifiedLowering::ToNumberCode() {
3395 if (!to_number_code_.is_set()) {
3396 Callable callable = CodeFactory::ToNumber(isolate());
3397 to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
3398 }
3399 return to_number_code_.get();
3400 }
3401
ToNumberOperator()3402 Operator const* SimplifiedLowering::ToNumberOperator() {
3403 if (!to_number_operator_.is_set()) {
3404 Callable callable = CodeFactory::ToNumber(isolate());
3405 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
3406 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
3407 isolate(), graph()->zone(), callable.descriptor(), 0, flags,
3408 Operator::kNoProperties);
3409 to_number_operator_.set(common()->Call(desc));
3410 }
3411 return to_number_operator_.get();
3412 }
3413
3414 } // namespace compiler
3415 } // namespace internal
3416 } // namespace v8
3417