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 "include/v8-fast-api-calls.h"
10 #include "src/base/bits.h"
11 #include "src/base/small-vector.h"
12 #include "src/codegen/code-factory.h"
13 #include "src/codegen/machine-type.h"
14 #include "src/codegen/tick-counter.h"
15 #include "src/compiler/access-builder.h"
16 #include "src/compiler/common-operator.h"
17 #include "src/compiler/compiler-source-position-table.h"
18 #include "src/compiler/diamond.h"
19 #include "src/compiler/graph-visualizer.h"
20 #include "src/compiler/js-heap-broker.h"
21 #include "src/compiler/linkage.h"
22 #include "src/compiler/node-matchers.h"
23 #include "src/compiler/node-observer.h"
24 #include "src/compiler/node-origin-table.h"
25 #include "src/compiler/operation-typer.h"
26 #include "src/compiler/operator-properties.h"
27 #include "src/compiler/representation-change.h"
28 #include "src/compiler/simplified-lowering-verifier.h"
29 #include "src/compiler/simplified-operator.h"
30 #include "src/compiler/type-cache.h"
31 #include "src/numbers/conversions-inl.h"
32 #include "src/objects/objects.h"
33 #include "src/utils/address-map.h"
34
35 #if V8_ENABLE_WEBASSEMBLY
36 #include "src/wasm/value-type.h"
37 #endif // V8_ENABLE_WEBASSEMBLY
38
39 namespace v8 {
40 namespace internal {
41 namespace compiler {
42
43 // Macro for outputting trace information from representation inference.
44 #define TRACE(...) \
45 do { \
46 if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
47 } while (false)
48
49 const char* kSimplifiedLoweringReducerName = "SimplifiedLowering";
50
51 // Representation selection and lowering of {Simplified} operators to machine
52 // operators are interwined. We use a fixpoint calculation to compute both the
53 // output representation and the best possible lowering for {Simplified} nodes.
54 // Representation change insertion ensures that all values are in the correct
55 // machine representation after this phase, as dictated by the machine
56 // operators themselves.
57 enum Phase {
58 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
59 // backwards from uses to definitions, around cycles in phis, according
60 // to local rules for each operator.
61 // During this phase, the usage information for a node determines the best
62 // possible lowering for each operator so far, and that in turn determines
63 // the output representation.
64 // Therefore, to be correct, this phase must iterate to a fixpoint before
65 // the next phase can begin.
66 PROPAGATE,
67
68 // 2.) RETYPE: Propagate types from type feedback forwards.
69 RETYPE,
70
71 // 3.) LOWER: perform lowering for all {Simplified} nodes by replacing some
72 // operators for some nodes, expanding some nodes to multiple nodes, or
73 // removing some (redundant) nodes.
74 // During this phase, use the {RepresentationChanger} to insert
75 // representation changes between uses that demand a particular
76 // representation and nodes that produce a different representation.
77 LOWER
78 };
79
80 namespace {
81
MachineRepresentationFromArrayType(ExternalArrayType array_type)82 MachineRepresentation MachineRepresentationFromArrayType(
83 ExternalArrayType array_type) {
84 switch (array_type) {
85 case kExternalUint8Array:
86 case kExternalUint8ClampedArray:
87 case kExternalInt8Array:
88 return MachineRepresentation::kWord8;
89 case kExternalUint16Array:
90 case kExternalInt16Array:
91 return MachineRepresentation::kWord16;
92 case kExternalUint32Array:
93 case kExternalInt32Array:
94 return MachineRepresentation::kWord32;
95 case kExternalFloat32Array:
96 return MachineRepresentation::kFloat32;
97 case kExternalFloat64Array:
98 return MachineRepresentation::kFloat64;
99 case kExternalBigInt64Array:
100 case kExternalBigUint64Array:
101 UNIMPLEMENTED();
102 }
103 UNREACHABLE();
104 }
105
CheckedUseInfoAsWord32FromHint(NumberOperationHint hint,IdentifyZeros identify_zeros=kDistinguishZeros,const FeedbackSource & feedback=FeedbackSource ())106 UseInfo CheckedUseInfoAsWord32FromHint(
107 NumberOperationHint hint, IdentifyZeros identify_zeros = kDistinguishZeros,
108 const FeedbackSource& feedback = FeedbackSource()) {
109 switch (hint) {
110 case NumberOperationHint::kSignedSmall:
111 case NumberOperationHint::kSignedSmallInputs:
112 return UseInfo::CheckedSignedSmallAsWord32(identify_zeros, feedback);
113 case NumberOperationHint::kNumber:
114 DCHECK_EQ(identify_zeros, kIdentifyZeros);
115 return UseInfo::CheckedNumberAsWord32(feedback);
116 case NumberOperationHint::kNumberOrBoolean:
117 // Not used currently.
118 UNREACHABLE();
119 case NumberOperationHint::kNumberOrOddball:
120 DCHECK_EQ(identify_zeros, kIdentifyZeros);
121 return UseInfo::CheckedNumberOrOddballAsWord32(feedback);
122 }
123 UNREACHABLE();
124 }
125
CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint,const FeedbackSource & feedback,IdentifyZeros identify_zeros=kDistinguishZeros)126 UseInfo CheckedUseInfoAsFloat64FromHint(
127 NumberOperationHint hint, const FeedbackSource& feedback,
128 IdentifyZeros identify_zeros = kDistinguishZeros) {
129 switch (hint) {
130 case NumberOperationHint::kSignedSmall:
131 case NumberOperationHint::kSignedSmallInputs:
132 // Not used currently.
133 UNREACHABLE();
134 case NumberOperationHint::kNumber:
135 return UseInfo::CheckedNumberAsFloat64(identify_zeros, feedback);
136 case NumberOperationHint::kNumberOrBoolean:
137 return UseInfo::CheckedNumberOrBooleanAsFloat64(identify_zeros, feedback);
138 case NumberOperationHint::kNumberOrOddball:
139 return UseInfo::CheckedNumberOrOddballAsFloat64(identify_zeros, feedback);
140 }
141 UNREACHABLE();
142 }
143
TruncatingUseInfoFromRepresentation(MachineRepresentation rep)144 UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
145 switch (rep) {
146 case MachineRepresentation::kTaggedSigned:
147 return UseInfo::TaggedSigned();
148 case MachineRepresentation::kTaggedPointer:
149 case MachineRepresentation::kTagged:
150 case MachineRepresentation::kMapWord:
151 return UseInfo::AnyTagged();
152 case MachineRepresentation::kFloat64:
153 return UseInfo::TruncatingFloat64();
154 case MachineRepresentation::kFloat32:
155 return UseInfo::Float32();
156 case MachineRepresentation::kWord8:
157 case MachineRepresentation::kWord16:
158 case MachineRepresentation::kWord32:
159 return UseInfo::TruncatingWord32();
160 case MachineRepresentation::kWord64:
161 return UseInfo::Word64();
162 case MachineRepresentation::kBit:
163 return UseInfo::Bool();
164 case MachineRepresentation::kCompressedPointer:
165 case MachineRepresentation::kCompressed:
166 case MachineRepresentation::kSandboxedPointer:
167 case MachineRepresentation::kSimd128:
168 case MachineRepresentation::kNone:
169 break;
170 }
171 UNREACHABLE();
172 }
173
UseInfoForBasePointer(const FieldAccess & access)174 UseInfo UseInfoForBasePointer(const FieldAccess& access) {
175 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
176 }
177
UseInfoForBasePointer(const ElementAccess & access)178 UseInfo UseInfoForBasePointer(const ElementAccess& access) {
179 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
180 }
181
ReplaceEffectControlUses(Node * node,Node * effect,Node * control)182 void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
183 for (Edge edge : node->use_edges()) {
184 if (NodeProperties::IsControlEdge(edge)) {
185 edge.UpdateTo(control);
186 } else if (NodeProperties::IsEffectEdge(edge)) {
187 edge.UpdateTo(effect);
188 } else {
189 DCHECK(NodeProperties::IsValueEdge(edge) ||
190 NodeProperties::IsContextEdge(edge));
191 }
192 }
193 }
194
CanOverflowSigned32(const Operator * op,Type left,Type right,TypeCache const * type_cache,Zone * type_zone)195 bool CanOverflowSigned32(const Operator* op, Type left, Type right,
196 TypeCache const* type_cache, Zone* type_zone) {
197 // We assume the inputs are checked Signed32 (or known statically to be
198 // Signed32). Technically, the inputs could also be minus zero, which we treat
199 // as 0 for the purpose of this function.
200 if (left.Maybe(Type::MinusZero())) {
201 left = Type::Union(left, type_cache->kSingletonZero, type_zone);
202 }
203 if (right.Maybe(Type::MinusZero())) {
204 right = Type::Union(right, type_cache->kSingletonZero, type_zone);
205 }
206 left = Type::Intersect(left, Type::Signed32(), type_zone);
207 right = Type::Intersect(right, Type::Signed32(), type_zone);
208 if (left.IsNone() || right.IsNone()) return false;
209 switch (op->opcode()) {
210 case IrOpcode::kSpeculativeSafeIntegerAdd:
211 return (left.Max() + right.Max() > kMaxInt) ||
212 (left.Min() + right.Min() < kMinInt);
213
214 case IrOpcode::kSpeculativeSafeIntegerSubtract:
215 return (left.Max() - right.Min() > kMaxInt) ||
216 (left.Min() - right.Max() < kMinInt);
217
218 default:
219 UNREACHABLE();
220 }
221 }
222
IsSomePositiveOrderedNumber(Type type)223 bool IsSomePositiveOrderedNumber(Type type) {
224 return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0);
225 }
226
227 class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter {
228 public:
JSONGraphWriterWithVerifierTypes(std::ostream & os,const Graph * graph,const SourcePositionTable * positions,const NodeOriginTable * origins,SimplifiedLoweringVerifier * verifier)229 JSONGraphWriterWithVerifierTypes(std::ostream& os, const Graph* graph,
230 const SourcePositionTable* positions,
231 const NodeOriginTable* origins,
232 SimplifiedLoweringVerifier* verifier)
233 : JSONGraphWriter(os, graph, positions, origins), verifier_(verifier) {}
234
235 protected:
GetType(Node * node)236 base::Optional<Type> GetType(Node* node) override {
237 return verifier_->GetType(node);
238 }
239
240 private:
241 SimplifiedLoweringVerifier* verifier_;
242 };
243
244 } // namespace
245
246 #ifdef DEBUG
247 // Helpers for monotonicity checking.
248 class InputUseInfos {
249 public:
InputUseInfos(Zone * zone)250 explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}
251
SetAndCheckInput(Node * node,int index,UseInfo use_info)252 void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
253 if (input_use_infos_.empty()) {
254 input_use_infos_.resize(node->InputCount(), UseInfo::None());
255 }
256 // Check that the new use informatin is a super-type of the old
257 // one.
258 DCHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
259 input_use_infos_[index] = use_info;
260 }
261
262 private:
263 ZoneVector<UseInfo> input_use_infos_;
264
IsUseLessGeneral(UseInfo use1,UseInfo use2)265 static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
266 return use1.truncation().IsLessGeneralThan(use2.truncation());
267 }
268 };
269
270 #endif // DEBUG
271
272 class RepresentationSelector {
273 // The purpose of this nested class is to hide method
274 // v8::internal::compiler::NodeProperties::ChangeOp which should not be
275 // directly used by code in RepresentationSelector and SimplifiedLowering.
276 // RepresentationSelector code should call RepresentationSelector::ChangeOp in
277 // place of NodeProperties::ChangeOp, in order to notify the changes to a
278 // registered ObserveNodeManager and support the %ObserveNode intrinsic.
279 class NodeProperties : public compiler::NodeProperties {
ChangeOp(Node * node,const Operator * new_op)280 static void ChangeOp(Node* node, const Operator* new_op) { UNREACHABLE(); }
281 };
282
283 public:
284 // Information for each node tracked during the fixpoint.
285 class NodeInfo final {
286 public:
287 // Adds new use to the node. Returns true if something has changed
288 // and the node has to be requeued.
AddUse(UseInfo info)289 bool AddUse(UseInfo info) {
290 Truncation old_truncation = truncation_;
291 truncation_ = Truncation::Generalize(truncation_, info.truncation());
292 return truncation_ != old_truncation;
293 }
294
set_queued()295 void set_queued() { state_ = kQueued; }
set_visited()296 void set_visited() { state_ = kVisited; }
set_pushed()297 void set_pushed() { state_ = kPushed; }
reset_state()298 void reset_state() { state_ = kUnvisited; }
visited() const299 bool visited() const { return state_ == kVisited; }
queued() const300 bool queued() const { return state_ == kQueued; }
pushed() const301 bool pushed() const { return state_ == kPushed; }
unvisited() const302 bool unvisited() const { return state_ == kUnvisited; }
truncation() const303 Truncation truncation() const { return truncation_; }
set_output(MachineRepresentation output)304 void set_output(MachineRepresentation output) { representation_ = output; }
305
representation() const306 MachineRepresentation representation() const { return representation_; }
307
308 // Helpers for feedback typing.
set_feedback_type(Type type)309 void set_feedback_type(Type type) { feedback_type_ = type; }
feedback_type() const310 Type feedback_type() const { return feedback_type_; }
set_weakened()311 void set_weakened() { weakened_ = true; }
weakened() const312 bool weakened() const { return weakened_; }
set_restriction_type(Type type)313 void set_restriction_type(Type type) { restriction_type_ = type; }
restriction_type() const314 Type restriction_type() const { return restriction_type_; }
315
316 private:
317 // Fields are ordered to avoid mixing byte and word size fields to minimize
318 // padding.
319 enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
320 State state_ = kUnvisited;
321 MachineRepresentation representation_ =
322 MachineRepresentation::kNone; // Output representation.
323 Truncation truncation_ = Truncation::None(); // Information about uses.
324 bool weakened_ = false;
325
326 Type restriction_type_ = Type::Any();
327 Type feedback_type_;
328 };
329
RepresentationSelector(JSGraph * jsgraph,JSHeapBroker * broker,Zone * zone,RepresentationChanger * changer,SourcePositionTable * source_positions,NodeOriginTable * node_origins,TickCounter * tick_counter,Linkage * linkage,ObserveNodeManager * observe_node_manager,SimplifiedLoweringVerifier * verifier)330 RepresentationSelector(JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
331 RepresentationChanger* changer,
332 SourcePositionTable* source_positions,
333 NodeOriginTable* node_origins,
334 TickCounter* tick_counter, Linkage* linkage,
335 ObserveNodeManager* observe_node_manager,
336 SimplifiedLoweringVerifier* verifier)
337 : jsgraph_(jsgraph),
338 broker_(broker),
339 zone_(zone),
340 might_need_revisit_(zone),
341 count_(jsgraph->graph()->NodeCount()),
342 info_(count_, zone),
343 #ifdef DEBUG
344 node_input_use_infos_(count_, InputUseInfos(zone), zone),
345 #endif
346 replacements_(zone),
347 changer_(changer),
348 revisit_queue_(zone),
349 traversal_nodes_(zone),
350 source_positions_(source_positions),
351 node_origins_(node_origins),
352 type_cache_(TypeCache::Get()),
353 op_typer_(broker, graph_zone()),
354 tick_counter_(tick_counter),
355 linkage_(linkage),
356 observe_node_manager_(observe_node_manager),
357 verifier_(verifier) {
358 }
359
verification_enabled() const360 bool verification_enabled() const { return verifier_ != nullptr; }
361
ResetNodeInfoState()362 void ResetNodeInfoState() {
363 // Clean up for the next phase.
364 for (NodeInfo& info : info_) {
365 info.reset_state();
366 }
367 }
368
TypeOf(Node * node)369 Type TypeOf(Node* node) {
370 Type type = GetInfo(node)->feedback_type();
371 return type.IsInvalid() ? NodeProperties::GetType(node) : type;
372 }
373
FeedbackTypeOf(Node * node)374 Type FeedbackTypeOf(Node* node) {
375 Type type = GetInfo(node)->feedback_type();
376 return type.IsInvalid() ? Type::None() : type;
377 }
378
TypePhi(Node * node)379 Type TypePhi(Node* node) {
380 int arity = node->op()->ValueInputCount();
381 Type type = FeedbackTypeOf(node->InputAt(0));
382 for (int i = 1; i < arity; ++i) {
383 type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
384 }
385 return type;
386 }
387
TypeSelect(Node * node)388 Type TypeSelect(Node* node) {
389 return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
390 FeedbackTypeOf(node->InputAt(2)));
391 }
392
UpdateFeedbackType(Node * node)393 bool UpdateFeedbackType(Node* node) {
394 if (node->op()->ValueOutputCount() == 0) return false;
395
396 // For any non-phi node just wait until we get all inputs typed. We only
397 // allow untyped inputs for phi nodes because phis are the only places
398 // where cycles need to be broken.
399 if (node->opcode() != IrOpcode::kPhi) {
400 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
401 if (GetInfo(node->InputAt(i))->feedback_type().IsInvalid()) {
402 return false;
403 }
404 }
405 }
406
407 NodeInfo* info = GetInfo(node);
408 Type type = info->feedback_type();
409 Type new_type = NodeProperties::GetType(node);
410
411 // We preload these values here to avoid increasing the binary size too
412 // much, which happens if we inline the calls into the macros below.
413 Type input0_type;
414 if (node->InputCount() > 0) input0_type = FeedbackTypeOf(node->InputAt(0));
415 Type input1_type;
416 if (node->InputCount() > 1) input1_type = FeedbackTypeOf(node->InputAt(1));
417
418 switch (node->opcode()) {
419 #define DECLARE_CASE(Name) \
420 case IrOpcode::k##Name: { \
421 new_type = op_typer_.Name(input0_type, input1_type); \
422 break; \
423 }
424 SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
425 DECLARE_CASE(SameValue)
426 #undef DECLARE_CASE
427
428 #define DECLARE_CASE(Name) \
429 case IrOpcode::k##Name: { \
430 new_type = Type::Intersect(op_typer_.Name(input0_type, input1_type), \
431 info->restriction_type(), graph_zone()); \
432 break; \
433 }
434 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
435 SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_CASE)
436 #undef DECLARE_CASE
437
438 #define DECLARE_CASE(Name) \
439 case IrOpcode::k##Name: { \
440 new_type = op_typer_.Name(input0_type); \
441 break; \
442 }
443 SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
444 #undef DECLARE_CASE
445
446 #define DECLARE_CASE(Name) \
447 case IrOpcode::k##Name: { \
448 new_type = Type::Intersect(op_typer_.Name(input0_type), \
449 info->restriction_type(), graph_zone()); \
450 break; \
451 }
452 SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
453 #undef DECLARE_CASE
454
455 case IrOpcode::kConvertReceiver:
456 new_type = op_typer_.ConvertReceiver(input0_type);
457 break;
458
459 case IrOpcode::kPlainPrimitiveToNumber:
460 new_type = op_typer_.ToNumber(input0_type);
461 break;
462
463 case IrOpcode::kCheckBounds:
464 new_type =
465 Type::Intersect(op_typer_.CheckBounds(input0_type, input1_type),
466 info->restriction_type(), graph_zone());
467 break;
468
469 case IrOpcode::kCheckFloat64Hole:
470 new_type = Type::Intersect(op_typer_.CheckFloat64Hole(input0_type),
471 info->restriction_type(), graph_zone());
472 break;
473
474 case IrOpcode::kCheckNumber:
475 new_type = Type::Intersect(op_typer_.CheckNumber(input0_type),
476 info->restriction_type(), graph_zone());
477 break;
478
479 case IrOpcode::kPhi: {
480 new_type = TypePhi(node);
481 if (!type.IsInvalid()) {
482 new_type = Weaken(node, type, new_type);
483 }
484 break;
485 }
486
487 case IrOpcode::kConvertTaggedHoleToUndefined:
488 new_type = op_typer_.ConvertTaggedHoleToUndefined(
489 FeedbackTypeOf(node->InputAt(0)));
490 break;
491
492 case IrOpcode::kTypeGuard: {
493 new_type = op_typer_.TypeTypeGuard(node->op(),
494 FeedbackTypeOf(node->InputAt(0)));
495 break;
496 }
497
498 case IrOpcode::kSelect: {
499 new_type = TypeSelect(node);
500 break;
501 }
502
503 default:
504 // Shortcut for operations that we do not handle.
505 if (type.IsInvalid()) {
506 GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
507 return true;
508 }
509 return false;
510 }
511 // We need to guarantee that the feedback type is a subtype of the upper
512 // bound. Naively that should hold, but weakening can actually produce
513 // a bigger type if we are unlucky with ordering of phi typing. To be
514 // really sure, just intersect the upper bound with the feedback type.
515 new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());
516
517 if (!type.IsInvalid() && new_type.Is(type)) return false;
518 GetInfo(node)->set_feedback_type(new_type);
519 if (FLAG_trace_representation) {
520 PrintNodeFeedbackType(node);
521 }
522 return true;
523 }
524
PrintNodeFeedbackType(Node * n)525 void PrintNodeFeedbackType(Node* n) {
526 StdoutStream os;
527 os << "#" << n->id() << ":" << *n->op() << "(";
528 int j = 0;
529 for (Node* const i : n->inputs()) {
530 if (j++ > 0) os << ", ";
531 os << "#" << i->id() << ":" << i->op()->mnemonic();
532 }
533 os << ")";
534 if (NodeProperties::IsTyped(n)) {
535 Type static_type = NodeProperties::GetType(n);
536 os << " [Static type: " << static_type;
537 Type feedback_type = GetInfo(n)->feedback_type();
538 if (!feedback_type.IsInvalid() && feedback_type != static_type) {
539 os << ", Feedback type: " << feedback_type;
540 }
541 os << "]";
542 }
543 os << std::endl;
544 }
545
Weaken(Node * node,Type previous_type,Type current_type)546 Type Weaken(Node* node, Type previous_type, Type current_type) {
547 // If the types have nothing to do with integers, return the types.
548 Type const integer = type_cache_->kInteger;
549 if (!previous_type.Maybe(integer)) {
550 return current_type;
551 }
552 DCHECK(current_type.Maybe(integer));
553
554 Type current_integer = Type::Intersect(current_type, integer, graph_zone());
555 DCHECK(!current_integer.IsNone());
556 Type previous_integer =
557 Type::Intersect(previous_type, integer, graph_zone());
558 DCHECK(!previous_integer.IsNone());
559
560 // Once we start weakening a node, we should always weaken.
561 if (!GetInfo(node)->weakened()) {
562 // Only weaken if there is range involved; we should converge quickly
563 // for all other types (the exception is a union of many constants,
564 // but we currently do not increase the number of constants in unions).
565 Type previous = previous_integer.GetRange();
566 Type current = current_integer.GetRange();
567 if (current.IsInvalid() || previous.IsInvalid()) {
568 return current_type;
569 }
570 // Range is involved => we are weakening.
571 GetInfo(node)->set_weakened();
572 }
573
574 return Type::Union(current_type,
575 op_typer_.WeakenRange(previous_integer, current_integer),
576 graph_zone());
577 }
578
579 // Generates a pre-order traversal of the nodes, starting with End.
GenerateTraversal()580 void GenerateTraversal() {
581 // Reset previous state.
582 ResetNodeInfoState();
583 traversal_nodes_.clear();
584 count_ = graph()->NodeCount();
585 info_.resize(count_);
586
587 ZoneStack<NodeState> stack(zone_);
588
589 stack.push({graph()->end(), 0});
590 GetInfo(graph()->end())->set_pushed();
591 while (!stack.empty()) {
592 NodeState& current = stack.top();
593 Node* node = current.node;
594
595 // If there is an unvisited input, push it and continue with that node.
596 bool pushed_unvisited = false;
597 while (current.input_index < node->InputCount()) {
598 Node* input = node->InputAt(current.input_index);
599 NodeInfo* input_info = GetInfo(input);
600 current.input_index++;
601 if (input_info->unvisited()) {
602 input_info->set_pushed();
603 stack.push({input, 0});
604 pushed_unvisited = true;
605 break;
606 } else if (input_info->pushed()) {
607 // Optimization for the Retype phase.
608 // If we had already pushed (and not visited) an input, it means that
609 // the current node will be visited in the Retype phase before one of
610 // its inputs. If this happens, the current node might need to be
611 // revisited.
612 MarkAsPossibleRevisit(node, input);
613 }
614 }
615
616 if (pushed_unvisited) continue;
617
618 stack.pop();
619 NodeInfo* info = GetInfo(node);
620 info->set_visited();
621
622 // Generate the traversal
623 traversal_nodes_.push_back(node);
624 }
625 }
626
PushNodeToRevisitIfVisited(Node * node)627 void PushNodeToRevisitIfVisited(Node* node) {
628 NodeInfo* info = GetInfo(node);
629 if (info->visited()) {
630 TRACE(" QUEUEING #%d: %s\n", node->id(), node->op()->mnemonic());
631 info->set_queued();
632 revisit_queue_.push(node);
633 }
634 }
635
636 // Tries to update the feedback type of the node, as well as setting its
637 // machine representation (in VisitNode). Returns true iff updating the
638 // feedback type is successful.
RetypeNode(Node * node)639 bool RetypeNode(Node* node) {
640 NodeInfo* info = GetInfo(node);
641 info->set_visited();
642 bool updated = UpdateFeedbackType(node);
643 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
644 VisitNode<RETYPE>(node, info->truncation(), nullptr);
645 TRACE(" ==> output %s\n", MachineReprToString(info->representation()));
646 return updated;
647 }
648
649 // Visits the node and marks it as visited. Inside of VisitNode, we might
650 // change the truncation of one of our inputs (see EnqueueInput<PROPAGATE> for
651 // this). If we change the truncation of an already visited node, we will add
652 // it to the revisit queue.
PropagateTruncation(Node * node)653 void PropagateTruncation(Node* node) {
654 NodeInfo* info = GetInfo(node);
655 info->set_visited();
656 TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
657 info->truncation().description());
658 VisitNode<PROPAGATE>(node, info->truncation(), nullptr);
659 }
660
661 // Backward propagation of truncations to a fixpoint.
RunPropagatePhase()662 void RunPropagatePhase() {
663 TRACE("--{Propagate phase}--\n");
664 ResetNodeInfoState();
665 DCHECK(revisit_queue_.empty());
666
667 // Process nodes in reverse post order, with End as the root.
668 for (auto it = traversal_nodes_.crbegin(); it != traversal_nodes_.crend();
669 ++it) {
670 PropagateTruncation(*it);
671
672 while (!revisit_queue_.empty()) {
673 Node* node = revisit_queue_.front();
674 revisit_queue_.pop();
675 PropagateTruncation(node);
676 }
677 }
678 }
679
680 // Forward propagation of types from type feedback to a fixpoint.
RunRetypePhase()681 void RunRetypePhase() {
682 TRACE("--{Retype phase}--\n");
683 ResetNodeInfoState();
684 DCHECK(revisit_queue_.empty());
685
686 for (auto it = traversal_nodes_.cbegin(); it != traversal_nodes_.cend();
687 ++it) {
688 Node* node = *it;
689 if (!RetypeNode(node)) continue;
690
691 auto revisit_it = might_need_revisit_.find(node);
692 if (revisit_it == might_need_revisit_.end()) continue;
693
694 for (Node* const user : revisit_it->second) {
695 PushNodeToRevisitIfVisited(user);
696 }
697
698 // Process the revisit queue.
699 while (!revisit_queue_.empty()) {
700 Node* revisit_node = revisit_queue_.front();
701 revisit_queue_.pop();
702 if (!RetypeNode(revisit_node)) continue;
703 // Here we need to check all uses since we can't easily know which
704 // nodes will need to be revisited due to having an input which was
705 // a revisited node.
706 for (Node* const user : revisit_node->uses()) {
707 PushNodeToRevisitIfVisited(user);
708 }
709 }
710 }
711 }
712
713 // Lowering and change insertion phase.
RunLowerPhase(SimplifiedLowering * lowering)714 void RunLowerPhase(SimplifiedLowering* lowering) {
715 TRACE("--{Lower phase}--\n");
716 for (auto it = traversal_nodes_.cbegin(); it != traversal_nodes_.cend();
717 ++it) {
718 Node* node = *it;
719 NodeInfo* info = GetInfo(node);
720 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
721 // Reuse {VisitNode()} so the representation rules are in one place.
722 SourcePositionTable::Scope scope(
723 source_positions_, source_positions_->GetSourcePosition(node));
724 NodeOriginTable::Scope origin_scope(node_origins_, "simplified lowering",
725 node);
726 VisitNode<LOWER>(node, info->truncation(), lowering);
727 }
728
729 // Perform the final replacements.
730 for (NodeVector::iterator i = replacements_.begin();
731 i != replacements_.end(); ++i) {
732 Node* node = *i;
733 Node* replacement = *(++i);
734 node->ReplaceUses(replacement);
735 node->Kill();
736 // We also need to replace the node in the rest of the vector.
737 for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
738 ++j;
739 if (*j == node) *j = replacement;
740 }
741 }
742 }
743
RunVerifyPhase(OptimizedCompilationInfo * info)744 void RunVerifyPhase(OptimizedCompilationInfo* info) {
745 DCHECK_NOT_NULL(verifier_);
746
747 TRACE("--{Verify Phase}--\n");
748
749 // Generate a new traversal containing all the new nodes created during
750 // lowering.
751 GenerateTraversal();
752
753 // Set node types to the refined types computed during retyping.
754 for (Node* node : traversal_nodes_) {
755 NodeInfo* info = GetInfo(node);
756 if (!info->feedback_type().IsInvalid()) {
757 NodeProperties::SetType(node, info->feedback_type());
758 }
759 }
760
761 // Verify all nodes.
762 for (Node* node : traversal_nodes_) verifier_->VisitNode(node, op_typer_);
763
764 // Print graph.
765 if (info != nullptr && info->trace_turbo_json()) {
766 UnparkedScopeIfNeeded scope(broker_);
767 AllowHandleDereference allow_deref;
768
769 TurboJsonFile json_of(info, std::ios_base::app);
770 JSONGraphWriterWithVerifierTypes writer(
771 json_of, graph(), source_positions_, node_origins_, verifier_);
772 writer.PrintPhase("V8.TFSimplifiedLoweringVerifier");
773 }
774
775 // Eliminate all introduced hints.
776 for (Node* node : verifier_->inserted_hints()) {
777 Node* input = node->InputAt(0);
778 node->ReplaceUses(input);
779 node->Kill();
780 }
781 }
782
Run(SimplifiedLowering * lowering)783 void Run(SimplifiedLowering* lowering) {
784 GenerateTraversal();
785 RunPropagatePhase();
786 RunRetypePhase();
787 RunLowerPhase(lowering);
788
789 if (verification_enabled()) {
790 RunVerifyPhase(lowering->info_);
791 }
792 }
793
794 // Just assert for Retype and Lower. Propagate specialized below.
795 template <Phase T>
EnqueueInput(Node * use_node,int index,UseInfo use_info=UseInfo::None ())796 void EnqueueInput(Node* use_node, int index,
797 UseInfo use_info = UseInfo::None()) {
798 static_assert(retype<T>() || lower<T>(),
799 "This version of EnqueueInput has to be called in "
800 "the Retype or Lower phase.");
801 }
802
803 template <Phase T>
propagate()804 static constexpr bool propagate() {
805 return T == PROPAGATE;
806 }
807
808 template <Phase T>
retype()809 static constexpr bool retype() {
810 return T == RETYPE;
811 }
812
813 template <Phase T>
lower()814 static constexpr bool lower() {
815 return T == LOWER;
816 }
817
818 template <Phase T>
819 void SetOutput(Node* node, MachineRepresentation representation,
820 Type restriction_type = Type::Any());
821
GetUpperBound(Node * node)822 Type GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
823
InputCannotBe(Node * node,Type type)824 bool InputCannotBe(Node* node, Type type) {
825 DCHECK_EQ(1, node->op()->ValueInputCount());
826 return !GetUpperBound(node->InputAt(0)).Maybe(type);
827 }
828
InputIs(Node * node,Type type)829 bool InputIs(Node* node, Type type) {
830 DCHECK_EQ(1, node->op()->ValueInputCount());
831 return GetUpperBound(node->InputAt(0)).Is(type);
832 }
833
BothInputsAreSigned32(Node * node)834 bool BothInputsAreSigned32(Node* node) {
835 return BothInputsAre(node, Type::Signed32());
836 }
837
BothInputsAreUnsigned32(Node * node)838 bool BothInputsAreUnsigned32(Node* node) {
839 return BothInputsAre(node, Type::Unsigned32());
840 }
841
BothInputsAre(Node * node,Type type)842 bool BothInputsAre(Node* node, Type type) {
843 DCHECK_EQ(2, node->op()->ValueInputCount());
844 return GetUpperBound(node->InputAt(0)).Is(type) &&
845 GetUpperBound(node->InputAt(1)).Is(type);
846 }
847
IsNodeRepresentationTagged(Node * node)848 bool IsNodeRepresentationTagged(Node* node) {
849 MachineRepresentation representation = GetInfo(node)->representation();
850 return IsAnyTagged(representation);
851 }
852
OneInputCannotBe(Node * node,Type type)853 bool OneInputCannotBe(Node* node, Type type) {
854 DCHECK_EQ(2, node->op()->ValueInputCount());
855 return !GetUpperBound(node->InputAt(0)).Maybe(type) ||
856 !GetUpperBound(node->InputAt(1)).Maybe(type);
857 }
858
ChangeToDeadValue(Node * node,Node * effect,Node * control)859 void ChangeToDeadValue(Node* node, Node* effect, Node* control) {
860 DCHECK(TypeOf(node).IsNone());
861 // If the node is unreachable, insert an Unreachable node and mark the
862 // value dead.
863 // TODO(jarin,turbofan) Find a way to unify/merge this insertion with
864 // InsertUnreachableIfNecessary.
865 Node* unreachable = effect =
866 graph()->NewNode(common()->Unreachable(), effect, control);
867 const Operator* dead_value =
868 common()->DeadValue(GetInfo(node)->representation());
869 node->ReplaceInput(0, unreachable);
870 node->TrimInputCount(dead_value->ValueInputCount());
871 ReplaceEffectControlUses(node, effect, control);
872 ChangeOp(node, dead_value);
873 }
874
875 // This function is a generalization of ChangeToPureOp. It can be used to
876 // replace a node that is part of the effect and control chain by a pure node.
ReplaceWithPureNode(Node * node,Node * pure_node)877 void ReplaceWithPureNode(Node* node, Node* pure_node) {
878 DCHECK(pure_node->op()->HasProperty(Operator::kPure));
879 if (node->op()->EffectInputCount() > 0) {
880 DCHECK_LT(0, node->op()->ControlInputCount());
881 Node* control = NodeProperties::GetControlInput(node);
882 Node* effect = NodeProperties::GetEffectInput(node);
883 if (TypeOf(node).IsNone()) {
884 ChangeToDeadValue(node, effect, control);
885 return;
886 }
887 // Rewire the effect and control chains.
888 ReplaceEffectControlUses(node, effect, control);
889 } else {
890 DCHECK_EQ(0, node->op()->ControlInputCount());
891 }
892 DeferReplacement(node, pure_node);
893 }
894
ChangeToPureOp(Node * node,const Operator * new_op)895 void ChangeToPureOp(Node* node, const Operator* new_op) {
896 DCHECK(new_op->HasProperty(Operator::kPure));
897 DCHECK_EQ(new_op->ValueInputCount(), node->op()->ValueInputCount());
898 if (node->op()->EffectInputCount() > 0) {
899 DCHECK_LT(0, node->op()->ControlInputCount());
900 Node* control = NodeProperties::GetControlInput(node);
901 Node* effect = NodeProperties::GetEffectInput(node);
902 if (TypeOf(node).IsNone()) {
903 ChangeToDeadValue(node, effect, control);
904 return;
905 }
906 // Rewire the effect and control chains.
907 node->TrimInputCount(new_op->ValueInputCount());
908 ReplaceEffectControlUses(node, effect, control);
909 } else {
910 DCHECK_EQ(0, node->op()->ControlInputCount());
911 }
912 ChangeOp(node, new_op);
913 }
914
ChangeUnaryToPureBinaryOp(Node * node,const Operator * new_op,int new_input_index,Node * new_input)915 void ChangeUnaryToPureBinaryOp(Node* node, const Operator* new_op,
916 int new_input_index, Node* new_input) {
917 DCHECK(new_op->HasProperty(Operator::kPure));
918 DCHECK_EQ(new_op->ValueInputCount(), 2);
919 DCHECK_EQ(node->op()->ValueInputCount(), 1);
920 DCHECK_LE(0, new_input_index);
921 DCHECK_LE(new_input_index, 1);
922 if (node->op()->EffectInputCount() > 0) {
923 DCHECK_LT(0, node->op()->ControlInputCount());
924 Node* control = NodeProperties::GetControlInput(node);
925 Node* effect = NodeProperties::GetEffectInput(node);
926 if (TypeOf(node).IsNone()) {
927 ChangeToDeadValue(node, effect, control);
928 return;
929 }
930 node->TrimInputCount(node->op()->ValueInputCount());
931 ReplaceEffectControlUses(node, effect, control);
932 } else {
933 DCHECK_EQ(0, node->op()->ControlInputCount());
934 }
935 if (new_input_index == 0) {
936 node->InsertInput(jsgraph_->zone(), 0, new_input);
937 } else {
938 DCHECK_EQ(new_input_index, 1);
939 DCHECK_EQ(node->InputCount(), 1);
940 node->AppendInput(jsgraph_->zone(), new_input);
941 }
942 ChangeOp(node, new_op);
943 }
944
945 // Converts input {index} of {node} according to given UseInfo {use},
946 // assuming the type of the input is {input_type}. If {input_type} is null,
947 // it takes the input from the input node {TypeOf(node->InputAt(index))}.
ConvertInput(Node * node,int index,UseInfo use,Type input_type=Type::Invalid ())948 void ConvertInput(Node* node, int index, UseInfo use,
949 Type input_type = Type::Invalid()) {
950 // In the change phase, insert a change before the use if necessary.
951 if (use.representation() == MachineRepresentation::kNone)
952 return; // No input requirement on the use.
953 Node* input = node->InputAt(index);
954 DCHECK_NOT_NULL(input);
955 NodeInfo* input_info = GetInfo(input);
956 MachineRepresentation input_rep = input_info->representation();
957 if (input_rep != use.representation() ||
958 use.type_check() != TypeCheckKind::kNone) {
959 // Output representation doesn't match usage.
960 TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
961 index, input->id(), input->op()->mnemonic());
962 TRACE("from %s to %s:%s\n",
963 MachineReprToString(input_info->representation()),
964 MachineReprToString(use.representation()),
965 use.truncation().description());
966 if (input_type.IsInvalid()) {
967 input_type = TypeOf(input);
968 }
969 Node* n = changer_->GetRepresentationFor(input, input_rep, input_type,
970 node, use);
971 node->ReplaceInput(index, n);
972 }
973 }
974
975 template <Phase T>
976 void ProcessInput(Node* node, int index, UseInfo use);
977
978 // Just assert for Retype and Lower. Propagate specialized below.
979 template <Phase T>
ProcessRemainingInputs(Node * node,int index)980 void ProcessRemainingInputs(Node* node, int index) {
981 static_assert(retype<T>() || lower<T>(),
982 "This version of ProcessRemainingInputs has to be called in "
983 "the Retype or Lower phase.");
984 DCHECK_GE(index, NodeProperties::PastValueIndex(node));
985 DCHECK_GE(index, NodeProperties::PastContextIndex(node));
986 }
987
988 // Marks node as a possible revisit since it is a use of input that will be
989 // visited before input is visited.
MarkAsPossibleRevisit(Node * node,Node * input)990 void MarkAsPossibleRevisit(Node* node, Node* input) {
991 auto it = might_need_revisit_.find(input);
992 if (it == might_need_revisit_.end()) {
993 it = might_need_revisit_.insert({input, ZoneVector<Node*>(zone())}).first;
994 }
995 it->second.push_back(node);
996 TRACE(" Marking #%d: %s as needing revisit due to #%d: %s\n", node->id(),
997 node->op()->mnemonic(), input->id(), input->op()->mnemonic());
998 }
999
1000 // Just assert for Retype. Propagate and Lower specialized below.
1001 template <Phase T>
VisitInputs(Node * node)1002 void VisitInputs(Node* node) {
1003 static_assert(
1004 retype<T>(),
1005 "This version of VisitInputs has to be called in the Retype phase.");
1006 }
1007
1008 template <Phase T>
VisitReturn(Node * node)1009 void VisitReturn(Node* node) {
1010 int first_effect_index = NodeProperties::FirstEffectIndex(node);
1011 // Visit integer slot count to pop
1012 ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());
1013
1014 // Visit value, context and frame state inputs as tagged.
1015 for (int i = 1; i < first_effect_index; i++) {
1016 ProcessInput<T>(node, i, UseInfo::AnyTagged());
1017 }
1018 // Only enqueue other inputs (effects, control).
1019 for (int i = first_effect_index; i < node->InputCount(); i++) {
1020 EnqueueInput<T>(node, i);
1021 }
1022 }
1023
1024 // Helper for an unused node.
1025 template <Phase T>
VisitUnused(Node * node)1026 void VisitUnused(Node* node) {
1027 int first_effect_index = NodeProperties::FirstEffectIndex(node);
1028 for (int i = 0; i < first_effect_index; i++) {
1029 ProcessInput<T>(node, i, UseInfo::None());
1030 }
1031 ProcessRemainingInputs<T>(node, first_effect_index);
1032
1033 if (lower<T>()) {
1034 TRACE("disconnecting unused #%d:%s\n", node->id(),
1035 node->op()->mnemonic());
1036 DisconnectFromEffectAndControl(node);
1037 node->NullAllInputs(); // Node is now dead.
1038 DeferReplacement(node, graph()->NewNode(common()->Plug()));
1039 }
1040 }
1041
1042 // Helper for no-op node.
1043 template <Phase T>
VisitNoop(Node * node,Truncation truncation)1044 void VisitNoop(Node* node, Truncation truncation) {
1045 if (truncation.IsUnused()) return VisitUnused<T>(node);
1046 MachineRepresentation representation =
1047 GetOutputInfoForPhi(node, TypeOf(node), truncation);
1048 VisitUnop<T>(node, UseInfo(representation, truncation), representation);
1049 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
1050 }
1051
1052 // Helper for binops of the R x L -> O variety.
1053 template <Phase T>
VisitBinop(Node * node,UseInfo left_use,UseInfo right_use,MachineRepresentation output,Type restriction_type=Type::Any ())1054 void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
1055 MachineRepresentation output,
1056 Type restriction_type = Type::Any()) {
1057 DCHECK_EQ(2, node->op()->ValueInputCount());
1058 ProcessInput<T>(node, 0, left_use);
1059 ProcessInput<T>(node, 1, right_use);
1060 for (int i = 2; i < node->InputCount(); i++) {
1061 EnqueueInput<T>(node, i);
1062 }
1063 SetOutput<T>(node, output, restriction_type);
1064 }
1065
1066 // Helper for binops of the I x I -> O variety.
1067 template <Phase T>
VisitBinop(Node * node,UseInfo input_use,MachineRepresentation output,Type restriction_type=Type::Any ())1068 void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output,
1069 Type restriction_type = Type::Any()) {
1070 VisitBinop<T>(node, input_use, input_use, output, restriction_type);
1071 }
1072
1073 template <Phase T>
VisitSpeculativeInt32Binop(Node * node)1074 void VisitSpeculativeInt32Binop(Node* node) {
1075 DCHECK_EQ(2, node->op()->ValueInputCount());
1076 if (BothInputsAre(node, Type::NumberOrOddball())) {
1077 return VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1078 MachineRepresentation::kWord32);
1079 }
1080 NumberOperationHint hint = NumberOperationHintOf(node->op());
1081 return VisitBinop<T>(node,
1082 CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
1083 MachineRepresentation::kWord32);
1084 }
1085
1086 // Helper for unops of the I -> O variety.
1087 template <Phase T>
VisitUnop(Node * node,UseInfo input_use,MachineRepresentation output,Type restriction_type=Type::Any ())1088 void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output,
1089 Type restriction_type = Type::Any()) {
1090 DCHECK_EQ(1, node->op()->ValueInputCount());
1091 ProcessInput<T>(node, 0, input_use);
1092 ProcessRemainingInputs<T>(node, 1);
1093 SetOutput<T>(node, output, restriction_type);
1094 }
1095
1096 // Helper for leaf nodes.
1097 template <Phase T>
VisitLeaf(Node * node,MachineRepresentation output)1098 void VisitLeaf(Node* node, MachineRepresentation output) {
1099 DCHECK_EQ(0, node->InputCount());
1100 SetOutput<T>(node, output);
1101 }
1102
1103 // Helpers for specific types of binops.
1104
1105 template <Phase T>
VisitFloat64Binop(Node * node)1106 void VisitFloat64Binop(Node* node) {
1107 VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
1108 MachineRepresentation::kFloat64);
1109 }
1110
1111 template <Phase T>
VisitInt64Binop(Node * node)1112 void VisitInt64Binop(Node* node) {
1113 VisitBinop<T>(node, UseInfo::Word64(), MachineRepresentation::kWord64);
1114 }
1115
1116 template <Phase T>
VisitWord32TruncatingBinop(Node * node)1117 void VisitWord32TruncatingBinop(Node* node) {
1118 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1119 MachineRepresentation::kWord32);
1120 }
1121
1122 // Infer representation for phi-like nodes.
1123 // The {node} parameter is only used to decide on the int64 representation.
1124 // Once the type system supports an external pointer type, the {node}
1125 // parameter can be removed.
GetOutputInfoForPhi(Node * node,Type type,Truncation use)1126 MachineRepresentation GetOutputInfoForPhi(Node* node, Type type,
1127 Truncation use) {
1128 // Compute the representation.
1129 if (type.Is(Type::None())) {
1130 return MachineRepresentation::kNone;
1131 } else if (type.Is(Type::Signed32()) || type.Is(Type::Unsigned32())) {
1132 return MachineRepresentation::kWord32;
1133 } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
1134 return MachineRepresentation::kWord32;
1135 } else if (type.Is(Type::Boolean())) {
1136 return MachineRepresentation::kBit;
1137 } else if (type.Is(Type::NumberOrOddball()) &&
1138 use.TruncatesOddballAndBigIntToNumber()) {
1139 return MachineRepresentation::kFloat64;
1140 } else if (type.Is(Type::Union(Type::SignedSmall(), Type::NaN(), zone()))) {
1141 // TODO(turbofan): For Phis that return either NaN or some Smi, it's
1142 // beneficial to not go all the way to double, unless the uses are
1143 // double uses. For tagging that just means some potentially expensive
1144 // allocation code; we might want to do the same for -0 as well?
1145 return MachineRepresentation::kTagged;
1146 } else if (type.Is(Type::Number())) {
1147 return MachineRepresentation::kFloat64;
1148 } else if (type.Is(Type::BigInt()) && use.IsUsedAsWord64()) {
1149 return MachineRepresentation::kWord64;
1150 } else if (type.Is(Type::ExternalPointer()) ||
1151 type.Is(Type::SandboxedPointer())) {
1152 return MachineType::PointerRepresentation();
1153 }
1154 return MachineRepresentation::kTagged;
1155 }
1156
1157 // Helper for handling selects.
1158 template <Phase T>
VisitSelect(Node * node,Truncation truncation,SimplifiedLowering * lowering)1159 void VisitSelect(Node* node, Truncation truncation,
1160 SimplifiedLowering* lowering) {
1161 DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
1162 ProcessInput<T>(node, 0, UseInfo::Bool());
1163
1164 MachineRepresentation output =
1165 GetOutputInfoForPhi(node, TypeOf(node), truncation);
1166 SetOutput<T>(node, output);
1167
1168 if (lower<T>()) {
1169 // Update the select operator.
1170 SelectParameters p = SelectParametersOf(node->op());
1171 if (output != p.representation()) {
1172 ChangeOp(node, lowering->common()->Select(output, p.hint()));
1173 }
1174 }
1175 // Convert inputs to the output representation of this phi, pass the
1176 // truncation truncation along.
1177 UseInfo input_use(output, truncation);
1178 ProcessInput<T>(node, 1, input_use);
1179 ProcessInput<T>(node, 2, input_use);
1180 }
1181
1182 // Helper for handling phis.
1183 template <Phase T>
VisitPhi(Node * node,Truncation truncation,SimplifiedLowering * lowering)1184 void VisitPhi(Node* node, Truncation truncation,
1185 SimplifiedLowering* lowering) {
1186 MachineRepresentation output =
1187 GetOutputInfoForPhi(node, TypeOf(node), truncation);
1188 // Only set the output representation if not running with type
1189 // feedback. (Feedback typing will set the representation.)
1190 SetOutput<T>(node, output);
1191
1192 int values = node->op()->ValueInputCount();
1193 if (lower<T>()) {
1194 // Update the phi operator.
1195 if (output != PhiRepresentationOf(node->op())) {
1196 ChangeOp(node, lowering->common()->Phi(output, values));
1197 }
1198 }
1199
1200 // Convert inputs to the output representation of this phi, pass the
1201 // truncation along.
1202 UseInfo input_use(output, truncation);
1203 for (int i = 0; i < node->InputCount(); i++) {
1204 ProcessInput<T>(node, i, i < values ? input_use : UseInfo::None());
1205 }
1206 }
1207
1208 template <Phase T>
VisitObjectIs(Node * node,Type type,SimplifiedLowering * lowering)1209 void VisitObjectIs(Node* node, Type type, SimplifiedLowering* lowering) {
1210 Type const input_type = TypeOf(node->InputAt(0));
1211 if (input_type.Is(type)) {
1212 VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
1213 if (lower<T>()) {
1214 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
1215 }
1216 } else {
1217 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
1218 if (lower<T>() && !input_type.Maybe(type)) {
1219 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1220 }
1221 }
1222 }
1223
1224 template <Phase T>
VisitCheck(Node * node,Type type,SimplifiedLowering * lowering)1225 void VisitCheck(Node* node, Type type, SimplifiedLowering* lowering) {
1226 if (InputIs(node, type)) {
1227 VisitUnop<T>(node, UseInfo::AnyTagged(),
1228 MachineRepresentation::kTaggedPointer);
1229 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
1230 } else {
1231 VisitUnop<T>(node,
1232 UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
1233 MachineRepresentation::kTaggedPointer);
1234 }
1235 }
1236
1237 template <Phase T>
VisitCall(Node * node,SimplifiedLowering * lowering)1238 void VisitCall(Node* node, SimplifiedLowering* lowering) {
1239 auto call_descriptor = CallDescriptorOf(node->op());
1240 int params = static_cast<int>(call_descriptor->ParameterCount());
1241 int value_input_count = node->op()->ValueInputCount();
1242
1243 DCHECK_GT(value_input_count, 0);
1244 DCHECK_GE(value_input_count, params);
1245
1246 // The target of the call.
1247 ProcessInput<T>(node, 0, UseInfo::Any());
1248
1249 // For the parameters (indexes [1, ..., params]), propagate representation
1250 // information from call descriptor.
1251 for (int i = 1; i <= params; i++) {
1252 ProcessInput<T>(node, i,
1253 TruncatingUseInfoFromRepresentation(
1254 call_descriptor->GetInputType(i).representation()));
1255 }
1256
1257 // Rest of the value inputs.
1258 for (int i = params + 1; i < value_input_count; i++) {
1259 ProcessInput<T>(node, i, UseInfo::AnyTagged());
1260 }
1261
1262 // Effect and Control.
1263 ProcessRemainingInputs<T>(node, value_input_count);
1264
1265 if (call_descriptor->ReturnCount() > 0) {
1266 SetOutput<T>(node, call_descriptor->GetReturnType(0).representation());
1267 } else {
1268 SetOutput<T>(node, MachineRepresentation::kTagged);
1269 }
1270 }
1271
MaskShiftOperand(Node * node,Type rhs_type)1272 void MaskShiftOperand(Node* node, Type rhs_type) {
1273 if (!rhs_type.Is(type_cache_->kZeroToThirtyOne)) {
1274 Node* const rhs = NodeProperties::GetValueInput(node, 1);
1275 node->ReplaceInput(1,
1276 graph()->NewNode(jsgraph_->machine()->Word32And(), rhs,
1277 jsgraph_->Int32Constant(0x1F)));
1278 }
1279 }
1280
DeoptValueSemanticOf(Type type)1281 static MachineSemantic DeoptValueSemanticOf(Type type) {
1282 // We only need signedness to do deopt correctly.
1283 if (type.Is(Type::Signed32())) {
1284 return MachineSemantic::kInt32;
1285 } else if (type.Is(Type::Unsigned32())) {
1286 return MachineSemantic::kUint32;
1287 } else {
1288 return MachineSemantic::kAny;
1289 }
1290 }
1291
DeoptMachineTypeOf(MachineRepresentation rep,Type type)1292 static MachineType DeoptMachineTypeOf(MachineRepresentation rep, Type type) {
1293 if (type.IsNone()) {
1294 return MachineType::None();
1295 }
1296 // Do not distinguish between various Tagged variations.
1297 if (IsAnyTagged(rep)) {
1298 return MachineType::AnyTagged();
1299 }
1300 if (rep == MachineRepresentation::kWord64) {
1301 if (type.Is(Type::BigInt())) {
1302 return MachineType::AnyTagged();
1303 }
1304
1305 DCHECK(type.Is(TypeCache::Get()->kSafeInteger));
1306 return MachineType(rep, MachineSemantic::kInt64);
1307 }
1308 MachineType machine_type(rep, DeoptValueSemanticOf(type));
1309 DCHECK(machine_type.representation() != MachineRepresentation::kWord32 ||
1310 machine_type.semantic() == MachineSemantic::kInt32 ||
1311 machine_type.semantic() == MachineSemantic::kUint32);
1312 DCHECK(machine_type.representation() != MachineRepresentation::kBit ||
1313 type.Is(Type::Boolean()));
1314 return machine_type;
1315 }
1316
1317 template <Phase T>
VisitStateValues(Node * node)1318 void VisitStateValues(Node* node) {
1319 if (propagate<T>()) {
1320 for (int i = 0; i < node->InputCount(); i++) {
1321 // When lowering 64 bit BigInts to Word64 representation, we have to
1322 // make sure they are rematerialized before deoptimization. By
1323 // propagating a AnyTagged use, the RepresentationChanger is going to
1324 // insert the necessary conversions.
1325 // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1326 // truncated BigInts.
1327 if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1328 EnqueueInput<T>(node, i, UseInfo::AnyTagged());
1329 } else {
1330 EnqueueInput<T>(node, i, UseInfo::Any());
1331 }
1332 }
1333 } else if (lower<T>()) {
1334 Zone* zone = jsgraph_->zone();
1335 ZoneVector<MachineType>* types =
1336 zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
1337 for (int i = 0; i < node->InputCount(); i++) {
1338 Node* input = node->InputAt(i);
1339 // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1340 // truncated BigInts.
1341 if (TypeOf(input).Is(Type::BigInt())) {
1342 ConvertInput(node, i, UseInfo::AnyTagged());
1343 }
1344
1345 (*types)[i] =
1346 DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1347 }
1348 SparseInputMask mask = SparseInputMaskOf(node->op());
1349 ChangeOp(node, common()->TypedStateValues(types, mask));
1350 }
1351 SetOutput<T>(node, MachineRepresentation::kTagged);
1352 }
1353
1354 template <Phase T>
VisitFrameState(FrameState node)1355 void VisitFrameState(FrameState node) {
1356 DCHECK_EQ(5, node->op()->ValueInputCount());
1357 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
1358 DCHECK_EQ(FrameState::kFrameStateInputCount, node->InputCount());
1359
1360 ProcessInput<T>(node, FrameState::kFrameStateParametersInput,
1361 UseInfo::AnyTagged());
1362 ProcessInput<T>(node, FrameState::kFrameStateLocalsInput,
1363 UseInfo::AnyTagged());
1364
1365 // Accumulator is a special flower - we need to remember its type in
1366 // a singleton typed-state-values node (as if it was a singleton
1367 // state-values node).
1368 Node* accumulator = node.stack();
1369 if (propagate<T>()) {
1370 // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1371 // truncated BigInts.
1372 if (TypeOf(accumulator).Is(Type::BigInt())) {
1373 EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
1374 UseInfo::AnyTagged());
1375 } else {
1376 EnqueueInput<T>(node, FrameState::kFrameStateStackInput,
1377 UseInfo::Any());
1378 }
1379 } else if (lower<T>()) {
1380 // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1381 // truncated BigInts.
1382 if (TypeOf(accumulator).Is(Type::BigInt())) {
1383 ConvertInput(node, FrameState::kFrameStateStackInput,
1384 UseInfo::AnyTagged());
1385 }
1386 Zone* zone = jsgraph_->zone();
1387 if (accumulator == jsgraph_->OptimizedOutConstant()) {
1388 node->ReplaceInput(FrameState::kFrameStateStackInput,
1389 jsgraph_->SingleDeadTypedStateValues());
1390 } else {
1391 ZoneVector<MachineType>* types =
1392 zone->New<ZoneVector<MachineType>>(1, zone);
1393 (*types)[0] = DeoptMachineTypeOf(GetInfo(accumulator)->representation(),
1394 TypeOf(accumulator));
1395
1396 node->ReplaceInput(
1397 FrameState::kFrameStateStackInput,
1398 jsgraph_->graph()->NewNode(
1399 common()->TypedStateValues(types, SparseInputMask::Dense()),
1400 node.stack()));
1401 }
1402 }
1403
1404 ProcessInput<T>(node, FrameState::kFrameStateContextInput,
1405 UseInfo::AnyTagged());
1406 ProcessInput<T>(node, FrameState::kFrameStateFunctionInput,
1407 UseInfo::AnyTagged());
1408 ProcessInput<T>(node, FrameState::kFrameStateOuterStateInput,
1409 UseInfo::AnyTagged());
1410 return SetOutput<T>(node, MachineRepresentation::kTagged);
1411 }
1412
1413 template <Phase T>
VisitObjectState(Node * node)1414 void VisitObjectState(Node* node) {
1415 if (propagate<T>()) {
1416 for (int i = 0; i < node->InputCount(); i++) {
1417 // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1418 // truncated BigInts.
1419 if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1420 EnqueueInput<T>(node, i, UseInfo::AnyTagged());
1421 } else {
1422 EnqueueInput<T>(node, i, UseInfo::Any());
1423 }
1424 }
1425 } else if (lower<T>()) {
1426 Zone* zone = jsgraph_->zone();
1427 ZoneVector<MachineType>* types =
1428 zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
1429 for (int i = 0; i < node->InputCount(); i++) {
1430 Node* input = node->InputAt(i);
1431 (*types)[i] =
1432 DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1433 // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
1434 // truncated BigInts.
1435 if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1436 ConvertInput(node, i, UseInfo::AnyTagged());
1437 }
1438 }
1439 ChangeOp(node, common()->TypedObjectState(ObjectIdOf(node->op()), types));
1440 }
1441 SetOutput<T>(node, MachineRepresentation::kTagged);
1442 }
1443
Int32Op(Node * node)1444 const Operator* Int32Op(Node* node) {
1445 return changer_->Int32OperatorFor(node->opcode());
1446 }
1447
Int32OverflowOp(Node * node)1448 const Operator* Int32OverflowOp(Node* node) {
1449 return changer_->Int32OverflowOperatorFor(node->opcode());
1450 }
1451
Int64Op(Node * node)1452 const Operator* Int64Op(Node* node) {
1453 return changer_->Int64OperatorFor(node->opcode());
1454 }
1455
Uint32Op(Node * node)1456 const Operator* Uint32Op(Node* node) {
1457 return changer_->Uint32OperatorFor(node->opcode());
1458 }
1459
Uint32OverflowOp(Node * node)1460 const Operator* Uint32OverflowOp(Node* node) {
1461 return changer_->Uint32OverflowOperatorFor(node->opcode());
1462 }
1463
Float64Op(Node * node)1464 const Operator* Float64Op(Node* node) {
1465 return changer_->Float64OperatorFor(node->opcode());
1466 }
1467
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,Type field_type,MachineRepresentation value_representation,Node * value)1468 WriteBarrierKind WriteBarrierKindFor(
1469 BaseTaggedness base_taggedness,
1470 MachineRepresentation field_representation, Type field_type,
1471 MachineRepresentation value_representation, Node* value) {
1472 if (base_taggedness == kTaggedBase &&
1473 CanBeTaggedPointer(field_representation)) {
1474 Type value_type = NodeProperties::GetType(value);
1475 if (value_representation == MachineRepresentation::kTaggedSigned) {
1476 // Write barriers are only for stores of heap objects.
1477 return kNoWriteBarrier;
1478 }
1479 if (field_type.Is(Type::BooleanOrNullOrUndefined()) ||
1480 value_type.Is(Type::BooleanOrNullOrUndefined())) {
1481 // Write barriers are not necessary when storing true, false, null or
1482 // undefined, because these special oddballs are always in the root set.
1483 return kNoWriteBarrier;
1484 }
1485 if (value_type.IsHeapConstant()) {
1486 RootIndex root_index;
1487 const RootsTable& roots_table = jsgraph_->isolate()->roots_table();
1488 if (roots_table.IsRootHandle(value_type.AsHeapConstant()->Value(),
1489 &root_index)) {
1490 if (RootsTable::IsImmortalImmovable(root_index)) {
1491 // Write barriers are unnecessary for immortal immovable roots.
1492 return kNoWriteBarrier;
1493 }
1494 }
1495 }
1496 if (field_representation == MachineRepresentation::kTaggedPointer ||
1497 value_representation == MachineRepresentation::kTaggedPointer) {
1498 // Write barriers for heap objects are cheaper.
1499 return kPointerWriteBarrier;
1500 }
1501 NumberMatcher m(value);
1502 if (m.HasResolvedValue()) {
1503 if (IsSmiDouble(m.ResolvedValue())) {
1504 // Storing a smi doesn't need a write barrier.
1505 return kNoWriteBarrier;
1506 }
1507 // The NumberConstant will be represented as HeapNumber.
1508 return kPointerWriteBarrier;
1509 }
1510 return kFullWriteBarrier;
1511 }
1512 return kNoWriteBarrier;
1513 }
1514
WriteBarrierKindFor(BaseTaggedness base_taggedness,MachineRepresentation field_representation,int field_offset,Type field_type,MachineRepresentation value_representation,Node * value)1515 WriteBarrierKind WriteBarrierKindFor(
1516 BaseTaggedness base_taggedness,
1517 MachineRepresentation field_representation, int field_offset,
1518 Type field_type, MachineRepresentation value_representation,
1519 Node* value) {
1520 WriteBarrierKind write_barrier_kind =
1521 WriteBarrierKindFor(base_taggedness, field_representation, field_type,
1522 value_representation, value);
1523 if (write_barrier_kind != kNoWriteBarrier) {
1524 if (base_taggedness == kTaggedBase &&
1525 field_offset == HeapObject::kMapOffset) {
1526 write_barrier_kind = kMapWriteBarrier;
1527 }
1528 }
1529 return write_barrier_kind;
1530 }
1531
graph() const1532 Graph* graph() const { return jsgraph_->graph(); }
common() const1533 CommonOperatorBuilder* common() const { return jsgraph_->common(); }
simplified() const1534 SimplifiedOperatorBuilder* simplified() const {
1535 return jsgraph_->simplified();
1536 }
1537
1538 template <Phase T>
VisitForCheckedInt32Mul(Node * node,Truncation truncation,Type input0_type,Type input1_type,UseInfo input_use)1539 void VisitForCheckedInt32Mul(Node* node, Truncation truncation,
1540 Type input0_type, Type input1_type,
1541 UseInfo input_use) {
1542 DCHECK_EQ(node->opcode(), IrOpcode::kSpeculativeNumberMultiply);
1543 // A -0 input is impossible or will cause a deopt.
1544 DCHECK(BothInputsAre(node, Type::Signed32()) ||
1545 !input_use.truncation().IdentifiesZeroAndMinusZero());
1546
1547 CheckForMinusZeroMode mz_mode;
1548 Type restriction;
1549 if (IsSomePositiveOrderedNumber(input0_type) ||
1550 IsSomePositiveOrderedNumber(input1_type)) {
1551 mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero;
1552 restriction = Type::Signed32();
1553 } else if (truncation.IdentifiesZeroAndMinusZero()) {
1554 mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero;
1555 restriction = Type::Signed32OrMinusZero();
1556 } else {
1557 mz_mode = CheckForMinusZeroMode::kCheckForMinusZero;
1558 restriction = Type::Signed32();
1559 }
1560
1561 VisitBinop<T>(node, input_use, MachineRepresentation::kWord32, restriction);
1562 if (lower<T>()) ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
1563 }
1564
ChangeToInt32OverflowOp(Node * node)1565 void ChangeToInt32OverflowOp(Node* node) {
1566 ChangeOp(node, Int32OverflowOp(node));
1567 }
1568
ChangeToUint32OverflowOp(Node * node)1569 void ChangeToUint32OverflowOp(Node* node) {
1570 ChangeOp(node, Uint32OverflowOp(node));
1571 }
1572
1573 template <Phase T>
VisitSpeculativeIntegerAdditiveOp(Node * node,Truncation truncation,SimplifiedLowering * lowering)1574 void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation,
1575 SimplifiedLowering* lowering) {
1576 Type left_upper = GetUpperBound(node->InputAt(0));
1577 Type right_upper = GetUpperBound(node->InputAt(1));
1578
1579 if (left_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1580 right_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero)) {
1581 // Only eliminate the node if its typing rule can be satisfied, namely
1582 // that a safe integer is produced.
1583 if (truncation.IsUnused()) return VisitUnused<T>(node);
1584
1585 // If we know how to interpret the result or if the users only care
1586 // about the low 32-bits, we can truncate to Word32 do a wrapping
1587 // addition.
1588 if (GetUpperBound(node).Is(Type::Signed32()) ||
1589 GetUpperBound(node).Is(Type::Unsigned32()) ||
1590 truncation.IsUsedAsWord32()) {
1591 // => Int32Add/Sub
1592 VisitWord32TruncatingBinop<T>(node);
1593 if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
1594 return;
1595 }
1596 }
1597
1598 // Try to use type feedback.
1599 NumberOperationHint const hint = NumberOperationHint::kSignedSmall;
1600 DCHECK_EQ(hint, NumberOperationHintOf(node->op()));
1601
1602 Type left_feedback_type = TypeOf(node->InputAt(0));
1603 Type right_feedback_type = TypeOf(node->InputAt(1));
1604
1605 // Using Signed32 as restriction type amounts to promising there won't be
1606 // signed overflow. This is incompatible with relying on a Word32 truncation
1607 // in order to skip the overflow check. Similarly, we must not drop -0 from
1608 // the result type unless we deopt for -0 inputs.
1609 Type const restriction =
1610 truncation.IsUsedAsWord32()
1611 ? Type::Any()
1612 : (truncation.identify_zeros() == kIdentifyZeros)
1613 ? Type::Signed32OrMinusZero()
1614 : Type::Signed32();
1615
1616 // Handle the case when no int32 checks on inputs are necessary (but
1617 // an overflow check is needed on the output). Note that we do not
1618 // have to do any check if at most one side can be minus zero. For
1619 // subtraction we need to handle the case of -0 - 0 properly, since
1620 // that can produce -0.
1621 Type left_constraint_type =
1622 node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd
1623 ? Type::Signed32OrMinusZero()
1624 : Type::Signed32();
1625 if (left_upper.Is(left_constraint_type) &&
1626 right_upper.Is(Type::Signed32OrMinusZero()) &&
1627 (left_upper.Is(Type::Signed32()) || right_upper.Is(Type::Signed32()))) {
1628 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1629 MachineRepresentation::kWord32, restriction);
1630 } else {
1631 // If the output's truncation is identify-zeros, we can pass it
1632 // along. Moreover, if the operation is addition and we know the
1633 // right-hand side is not minus zero, we do not have to distinguish
1634 // between 0 and -0.
1635 IdentifyZeros left_identify_zeros = truncation.identify_zeros();
1636 if (node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd &&
1637 !right_feedback_type.Maybe(Type::MinusZero())) {
1638 left_identify_zeros = kIdentifyZeros;
1639 }
1640 UseInfo left_use =
1641 CheckedUseInfoAsWord32FromHint(hint, left_identify_zeros);
1642 // For CheckedInt32Add and CheckedInt32Sub, we don't need to do
1643 // a minus zero check for the right hand side, since we already
1644 // know that the left hand side is a proper Signed32 value,
1645 // potentially guarded by a check.
1646 UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros);
1647 VisitBinop<T>(node, left_use, right_use, MachineRepresentation::kWord32,
1648 restriction);
1649 }
1650
1651 if (lower<T>()) {
1652 if (truncation.IsUsedAsWord32() ||
1653 !CanOverflowSigned32(node->op(), left_feedback_type,
1654 right_feedback_type, type_cache_,
1655 graph_zone())) {
1656 ChangeToPureOp(node, Int32Op(node));
1657 } else {
1658 ChangeToInt32OverflowOp(node);
1659 }
1660 }
1661 return;
1662 }
1663
1664 template <Phase T>
VisitSpeculativeAdditiveOp(Node * node,Truncation truncation,SimplifiedLowering * lowering)1665 void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
1666 SimplifiedLowering* lowering) {
1667 if (BothInputsAre(node, type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1668 (GetUpperBound(node).Is(Type::Signed32()) ||
1669 GetUpperBound(node).Is(Type::Unsigned32()) ||
1670 truncation.IsUsedAsWord32())) {
1671 // => Int32Add/Sub
1672 VisitWord32TruncatingBinop<T>(node);
1673 if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
1674 return;
1675 }
1676
1677 // default case => Float64Add/Sub
1678 VisitBinop<T>(node,
1679 UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1680 FeedbackSource()),
1681 MachineRepresentation::kFloat64, Type::Number());
1682 if (lower<T>()) {
1683 ChangeToPureOp(node, Float64Op(node));
1684 }
1685 return;
1686 }
1687
1688 template <Phase T>
VisitSpeculativeNumberModulus(Node * node,Truncation truncation,SimplifiedLowering * lowering)1689 void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
1690 SimplifiedLowering* lowering) {
1691 if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
1692 (truncation.IsUsedAsWord32() ||
1693 NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1694 // => unsigned Uint32Mod
1695 VisitWord32TruncatingBinop<T>(node);
1696 if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
1697 return;
1698 }
1699 if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
1700 (truncation.IsUsedAsWord32() ||
1701 NodeProperties::GetType(node).Is(Type::Signed32()))) {
1702 // => signed Int32Mod
1703 VisitWord32TruncatingBinop<T>(node);
1704 if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1705 return;
1706 }
1707
1708 // Try to use type feedback.
1709 NumberOperationHint hint = NumberOperationHintOf(node->op());
1710
1711 // Handle the case when no uint32 checks on inputs are necessary
1712 // (but an overflow check is needed on the output).
1713 if (BothInputsAreUnsigned32(node)) {
1714 if (hint == NumberOperationHint::kSignedSmall) {
1715 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1716 MachineRepresentation::kWord32, Type::Unsigned32());
1717 if (lower<T>()) ChangeToUint32OverflowOp(node);
1718 return;
1719 }
1720 }
1721
1722 // Handle the case when no int32 checks on inputs are necessary
1723 // (but an overflow check is needed on the output).
1724 if (BothInputsAre(node, Type::Signed32())) {
1725 // If both the inputs the feedback are int32, use the overflow op.
1726 if (hint == NumberOperationHint::kSignedSmall) {
1727 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1728 MachineRepresentation::kWord32, Type::Signed32());
1729 if (lower<T>()) ChangeToInt32OverflowOp(node);
1730 return;
1731 }
1732 }
1733
1734 if (hint == NumberOperationHint::kSignedSmall) {
1735 // If the result is truncated, we only need to check the inputs.
1736 // For the left hand side we just propagate the identify zeros
1737 // mode of the {truncation}; and for modulus the sign of the
1738 // right hand side doesn't matter anyways, so in particular there's
1739 // no observable difference between a 0 and a -0 then.
1740 UseInfo const lhs_use =
1741 CheckedUseInfoAsWord32FromHint(hint, truncation.identify_zeros());
1742 UseInfo const rhs_use =
1743 CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros);
1744 if (truncation.IsUsedAsWord32()) {
1745 VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
1746 if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1747 } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
1748 Type const restriction =
1749 truncation.IdentifiesZeroAndMinusZero() &&
1750 TypeOf(node->InputAt(0)).Maybe(Type::MinusZero())
1751 ? Type::Unsigned32OrMinusZero()
1752 : Type::Unsigned32();
1753 VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
1754 restriction);
1755 if (lower<T>()) ChangeToUint32OverflowOp(node);
1756 } else {
1757 Type const restriction =
1758 truncation.IdentifiesZeroAndMinusZero() &&
1759 TypeOf(node->InputAt(0)).Maybe(Type::MinusZero())
1760 ? Type::Signed32OrMinusZero()
1761 : Type::Signed32();
1762 VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
1763 restriction);
1764 if (lower<T>()) ChangeToInt32OverflowOp(node);
1765 }
1766 return;
1767 }
1768
1769 if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
1770 TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
1771 (truncation.IsUsedAsWord32() ||
1772 NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1773 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1774 MachineRepresentation::kWord32, Type::Number());
1775 if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
1776 return;
1777 }
1778 if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
1779 TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
1780 (truncation.IsUsedAsWord32() ||
1781 NodeProperties::GetType(node).Is(Type::Signed32()))) {
1782 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1783 MachineRepresentation::kWord32, Type::Number());
1784 if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1785 return;
1786 }
1787
1788 // default case => Float64Mod
1789 // For the left hand side we just propagate the identify zeros
1790 // mode of the {truncation}; and for modulus the sign of the
1791 // right hand side doesn't matter anyways, so in particular there's
1792 // no observable difference between a 0 and a -0 then.
1793 UseInfo const lhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1794 truncation.identify_zeros(), FeedbackSource());
1795 UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1796 kIdentifyZeros, FeedbackSource());
1797 VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
1798 Type::Number());
1799 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
1800 return;
1801 }
1802
1803 // Just assert for Propagate and Retype. Lower specialized below.
1804 template <Phase T>
InsertUnreachableIfNecessary(Node * node)1805 void InsertUnreachableIfNecessary(Node* node) {
1806 static_assert(propagate<T>() || retype<T>(),
1807 "This version of InsertUnreachableIfNecessary has to be "
1808 "called in the Propagate or Retype phase.");
1809 }
1810
1811 template <Phase T>
VisitCheckBounds(Node * node,SimplifiedLowering * lowering)1812 void VisitCheckBounds(Node* node, SimplifiedLowering* lowering) {
1813 CheckBoundsParameters const& p = CheckBoundsParametersOf(node->op());
1814 FeedbackSource const& feedback = p.check_parameters().feedback();
1815 Type const index_type = TypeOf(node->InputAt(0));
1816 Type const length_type = TypeOf(node->InputAt(1));
1817
1818 // Conversions, if requested and needed, will be handled by the
1819 // representation changer, not by the lower-level Checked*Bounds operators.
1820 CheckBoundsFlags new_flags =
1821 p.flags().without(CheckBoundsFlag::kConvertStringAndMinusZero);
1822
1823 if (length_type.Is(Type::Unsigned31())) {
1824 if (index_type.Is(Type::Integral32()) ||
1825 (index_type.Is(Type::Integral32OrMinusZero()) &&
1826 p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero)) {
1827 // Map the values in the [-2^31,-1] range to the [2^31,2^32-1] range,
1828 // which will be considered out-of-bounds because the {length_type} is
1829 // limited to Unsigned31. This also converts -0 to 0.
1830 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1831 MachineRepresentation::kWord32);
1832 if (lower<T>()) {
1833 if (index_type.IsNone() || length_type.IsNone() ||
1834 (index_type.Min() >= 0.0 &&
1835 index_type.Max() < length_type.Min())) {
1836 // The bounds check is redundant if we already know that
1837 // the index is within the bounds of [0.0, length[.
1838 // TODO(neis): Move this into TypedOptimization?
1839 new_flags |= CheckBoundsFlag::kAbortOnOutOfBounds;
1840 }
1841 ChangeOp(node,
1842 simplified()->CheckedUint32Bounds(feedback, new_flags));
1843 }
1844 } else if (p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero) {
1845 VisitBinop<T>(node, UseInfo::CheckedTaggedAsArrayIndex(feedback),
1846 UseInfo::Word(), MachineType::PointerRepresentation());
1847 if (lower<T>()) {
1848 if (jsgraph_->machine()->Is64()) {
1849 ChangeOp(node,
1850 simplified()->CheckedUint64Bounds(feedback, new_flags));
1851 } else {
1852 ChangeOp(node,
1853 simplified()->CheckedUint32Bounds(feedback, new_flags));
1854 }
1855 }
1856 } else {
1857 VisitBinop<T>(
1858 node, UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, feedback),
1859 UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
1860 if (lower<T>()) {
1861 ChangeOp(node,
1862 simplified()->CheckedUint32Bounds(feedback, new_flags));
1863 }
1864 }
1865 } else {
1866 CHECK(length_type.Is(type_cache_->kPositiveSafeInteger));
1867 IdentifyZeros zero_handling =
1868 (p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero)
1869 ? kIdentifyZeros
1870 : kDistinguishZeros;
1871 VisitBinop<T>(node,
1872 UseInfo::CheckedSigned64AsWord64(zero_handling, feedback),
1873 UseInfo::Word64(), MachineRepresentation::kWord64);
1874 if (lower<T>()) {
1875 ChangeOp(node, simplified()->CheckedUint64Bounds(feedback, new_flags));
1876 }
1877 }
1878 }
1879
UseInfoForFastApiCallArgument(CTypeInfo type,FeedbackSource const & feedback)1880 UseInfo UseInfoForFastApiCallArgument(CTypeInfo type,
1881 FeedbackSource const& feedback) {
1882 switch (type.GetSequenceType()) {
1883 case CTypeInfo::SequenceType::kScalar: {
1884 switch (type.GetType()) {
1885 case CTypeInfo::Type::kVoid:
1886 UNREACHABLE();
1887 case CTypeInfo::Type::kBool:
1888 return UseInfo::Bool();
1889 case CTypeInfo::Type::kInt32:
1890 case CTypeInfo::Type::kUint32:
1891 return UseInfo::CheckedNumberAsWord32(feedback);
1892 // TODO(mslekova): We deopt for unsafe integers, but ultimately we
1893 // want to make this less restrictive in order to stay on the fast
1894 // path.
1895 case CTypeInfo::Type::kInt64:
1896 case CTypeInfo::Type::kUint64:
1897 case CTypeInfo::Type::kAny:
1898 return UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, feedback);
1899 case CTypeInfo::Type::kFloat32:
1900 case CTypeInfo::Type::kFloat64:
1901 return UseInfo::CheckedNumberAsFloat64(kDistinguishZeros, feedback);
1902 case CTypeInfo::Type::kV8Value:
1903 case CTypeInfo::Type::kApiObject:
1904 return UseInfo::AnyTagged();
1905 }
1906 }
1907 case CTypeInfo::SequenceType::kIsSequence: {
1908 CHECK_EQ(type.GetType(), CTypeInfo::Type::kVoid);
1909 return UseInfo::AnyTagged();
1910 }
1911 case CTypeInfo::SequenceType::kIsTypedArray: {
1912 return UseInfo::AnyTagged();
1913 }
1914 default: {
1915 UNREACHABLE(); // TODO(mslekova): Implement array buffers.
1916 }
1917 }
1918 }
1919
1920 static constexpr int kInitialArgumentsCount = 10;
1921
1922 template <Phase T>
VisitFastApiCall(Node * node,SimplifiedLowering * lowering)1923 void VisitFastApiCall(Node* node, SimplifiedLowering* lowering) {
1924 FastApiCallParameters const& op_params =
1925 FastApiCallParametersOf(node->op());
1926 // We only consider the first function signature here. In case of function
1927 // overloads, we only support the case of two functions that differ for one
1928 // argument, which must be a JSArray in one function and a TypedArray in the
1929 // other function, and both JSArrays and TypedArrays have the same UseInfo
1930 // UseInfo::AnyTagged(). All the other argument types must match.
1931 const CFunctionInfo* c_signature = op_params.c_functions()[0].signature;
1932 const int c_arg_count = c_signature->ArgumentCount();
1933 CallDescriptor* call_descriptor = op_params.descriptor();
1934 int js_arg_count = static_cast<int>(call_descriptor->ParameterCount());
1935 const int value_input_count = node->op()->ValueInputCount();
1936 CHECK_EQ(FastApiCallNode::ArityForArgc(c_arg_count, js_arg_count),
1937 value_input_count);
1938
1939 base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
1940 c_arg_count);
1941 // Propagate representation information from TypeInfo.
1942 for (int i = 0; i < c_arg_count; i++) {
1943 arg_use_info[i] = UseInfoForFastApiCallArgument(
1944 c_signature->ArgumentInfo(i), op_params.feedback());
1945 ProcessInput<T>(node, i, arg_use_info[i]);
1946 }
1947
1948 // The call code for the slow call.
1949 ProcessInput<T>(node, c_arg_count, UseInfo::AnyTagged());
1950 for (int i = 1; i <= js_arg_count; i++) {
1951 ProcessInput<T>(node, c_arg_count + i,
1952 TruncatingUseInfoFromRepresentation(
1953 call_descriptor->GetInputType(i).representation()));
1954 }
1955 for (int i = c_arg_count + js_arg_count; i < value_input_count; ++i) {
1956 ProcessInput<T>(node, i, UseInfo::AnyTagged());
1957 }
1958 ProcessRemainingInputs<T>(node, value_input_count);
1959 SetOutput<T>(node, MachineRepresentation::kTagged);
1960 }
1961
1962 #if V8_ENABLE_WEBASSEMBLY
MachineTypeForWasmReturnType(wasm::ValueType type)1963 static MachineType MachineTypeForWasmReturnType(wasm::ValueType type) {
1964 switch (type.kind()) {
1965 case wasm::kI32:
1966 return MachineType::Int32();
1967 case wasm::kF32:
1968 return MachineType::Float32();
1969 case wasm::kF64:
1970 return MachineType::Float64();
1971 case wasm::kI64:
1972 // Not used for i64, see VisitJSWasmCall().
1973 default:
1974 UNREACHABLE();
1975 }
1976 }
1977
UseInfoForJSWasmCallArgument(Node * input,wasm::ValueType type,FeedbackSource const & feedback)1978 UseInfo UseInfoForJSWasmCallArgument(Node* input, wasm::ValueType type,
1979 FeedbackSource const& feedback) {
1980 // If the input type is a Number or Oddball, we can directly convert the
1981 // input into the Wasm native type of the argument. If not, we return
1982 // UseInfo::AnyTagged to signal that WasmWrapperGraphBuilder will need to
1983 // add Nodes to perform the conversion (in WasmWrapperGraphBuilder::FromJS).
1984 switch (type.kind()) {
1985 case wasm::kI32:
1986 return UseInfo::CheckedNumberOrOddballAsWord32(feedback);
1987 case wasm::kI64:
1988 return UseInfo::AnyTagged();
1989 case wasm::kF32:
1990 case wasm::kF64:
1991 // For Float32, TruncateFloat64ToFloat32 will be inserted later in
1992 // WasmWrapperGraphBuilder::BuildJSToWasmWrapper.
1993 return UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
1994 feedback);
1995 default:
1996 UNREACHABLE();
1997 }
1998 }
1999
2000 template <Phase T>
VisitJSWasmCall(Node * node,SimplifiedLowering * lowering)2001 void VisitJSWasmCall(Node* node, SimplifiedLowering* lowering) {
2002 DCHECK_EQ(JSWasmCallNode::TargetIndex(), 0);
2003 DCHECK_EQ(JSWasmCallNode::ReceiverIndex(), 1);
2004 DCHECK_EQ(JSWasmCallNode::FirstArgumentIndex(), 2);
2005
2006 JSWasmCallNode n(node);
2007
2008 JSWasmCallParameters const& params = n.Parameters();
2009 const wasm::FunctionSig* wasm_signature = params.signature();
2010 int wasm_arg_count = static_cast<int>(wasm_signature->parameter_count());
2011 DCHECK_EQ(wasm_arg_count, n.ArgumentCount());
2012
2013 base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
2014 wasm_arg_count);
2015
2016 // Visit JSFunction and Receiver nodes.
2017 ProcessInput<T>(node, JSWasmCallNode::TargetIndex(), UseInfo::Any());
2018 ProcessInput<T>(node, JSWasmCallNode::ReceiverIndex(), UseInfo::Any());
2019
2020 // Propagate representation information from TypeInfo.
2021 for (int i = 0; i < wasm_arg_count; i++) {
2022 TNode<Object> input = n.Argument(i);
2023 DCHECK_NOT_NULL(input);
2024 arg_use_info[i] = UseInfoForJSWasmCallArgument(
2025 input, wasm_signature->GetParam(i), params.feedback());
2026 ProcessInput<T>(node, JSWasmCallNode::ArgumentIndex(i), arg_use_info[i]);
2027 }
2028
2029 // Visit value, context and frame state inputs as tagged.
2030 int first_effect_index = NodeProperties::FirstEffectIndex(node);
2031 DCHECK(first_effect_index >
2032 JSWasmCallNode::FirstArgumentIndex() + wasm_arg_count);
2033 for (int i = JSWasmCallNode::FirstArgumentIndex() + wasm_arg_count;
2034 i < first_effect_index; i++) {
2035 ProcessInput<T>(node, i, UseInfo::AnyTagged());
2036 }
2037
2038 // Effect and Control.
2039 ProcessRemainingInputs<T>(node, NodeProperties::FirstEffectIndex(node));
2040
2041 if (wasm_signature->return_count() == 1) {
2042 if (wasm_signature->GetReturn().kind() == wasm::kI64) {
2043 // Conversion between negative int64 and BigInt not supported yet.
2044 // Do not bypass the type conversion when the result type is i64.
2045 SetOutput<T>(node, MachineRepresentation::kTagged);
2046 } else {
2047 MachineType return_type =
2048 MachineTypeForWasmReturnType(wasm_signature->GetReturn());
2049 SetOutput<T>(
2050 node, return_type.representation(),
2051 JSWasmCallNode::TypeForWasmReturnType(wasm_signature->GetReturn()));
2052 }
2053 } else {
2054 DCHECK_EQ(wasm_signature->return_count(), 0);
2055 SetOutput<T>(node, MachineRepresentation::kTagged);
2056 }
2057
2058 // The actual lowering of JSWasmCall nodes happens later, in the subsequent
2059 // "wasm-inlining" phase.
2060 }
2061 #endif // V8_ENABLE_WEBASSEMBLY
2062
2063 // Dispatching routine for visiting the node {node} with the usage {use}.
2064 // Depending on the operator, propagate new usage info to the inputs.
2065 template <Phase T>
VisitNode(Node * node,Truncation truncation,SimplifiedLowering * lowering)2066 void VisitNode(Node* node, Truncation truncation,
2067 SimplifiedLowering* lowering) {
2068 tick_counter_->TickAndMaybeEnterSafepoint();
2069
2070 if (lower<T>()) {
2071 // Kill non-effectful operations that have a None-type input and are thus
2072 // dead code. Otherwise we might end up lowering the operation in a way,
2073 // e.g. by replacing it with a constant, that cuts the dependency on a
2074 // deopting operation (the producer of the None type), possibly resulting
2075 // in a nonsense schedule.
2076 if (node->op()->EffectOutputCount() == 0 &&
2077 node->op()->ControlOutputCount() == 0 &&
2078 node->opcode() != IrOpcode::kDeadValue &&
2079 node->opcode() != IrOpcode::kStateValues &&
2080 node->opcode() != IrOpcode::kFrameState &&
2081 node->opcode() != IrOpcode::kPhi) {
2082 for (int i = 0; i < node->op()->ValueInputCount(); i++) {
2083 Node* input = node->InputAt(i);
2084 if (TypeOf(input).IsNone()) {
2085 node->ReplaceInput(0, input);
2086 node->TrimInputCount(1);
2087 ChangeOp(node,
2088 common()->DeadValue(GetInfo(node)->representation()));
2089 return;
2090 }
2091 }
2092 } else {
2093 InsertUnreachableIfNecessary<T>(node);
2094 }
2095 }
2096
2097 // Unconditionally eliminate unused pure nodes (only relevant if there's
2098 // a pure operation in between two effectful ones, where the last one
2099 // is unused).
2100 // Note: We must not do this for constants, as they are cached and we
2101 // would thus kill the cached {node} during lowering (i.e. replace all
2102 // uses with Dead), but at that point some node lowering might have
2103 // already taken the constant {node} from the cache (while it was not
2104 // yet killed) and we would afterwards replace that use with Dead as well.
2105 if (node->op()->ValueInputCount() > 0 &&
2106 node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) {
2107 return VisitUnused<T>(node);
2108 }
2109
2110 switch (node->opcode()) {
2111 //------------------------------------------------------------------
2112 // Common operators.
2113 //------------------------------------------------------------------
2114 case IrOpcode::kStart:
2115 // We use Start as a terminator for the frame state chain, so even
2116 // tho Start doesn't really produce a value, we have to say Tagged
2117 // here, otherwise the input conversion will fail.
2118 return VisitLeaf<T>(node, MachineRepresentation::kTagged);
2119 case IrOpcode::kParameter:
2120 return VisitUnop<T>(node, UseInfo::None(),
2121 linkage()
2122 ->GetParameterType(ParameterIndexOf(node->op()))
2123 .representation());
2124 case IrOpcode::kInt32Constant:
2125 return VisitLeaf<T>(node, MachineRepresentation::kWord32);
2126 case IrOpcode::kInt64Constant:
2127 return VisitLeaf<T>(node, MachineRepresentation::kWord64);
2128 case IrOpcode::kExternalConstant:
2129 return VisitLeaf<T>(node, MachineType::PointerRepresentation());
2130 case IrOpcode::kNumberConstant: {
2131 double const value = OpParameter<double>(node->op());
2132 int value_as_int;
2133 if (DoubleToSmiInteger(value, &value_as_int)) {
2134 VisitLeaf<T>(node, MachineRepresentation::kTaggedSigned);
2135 if (lower<T>()) {
2136 intptr_t smi = bit_cast<intptr_t>(Smi::FromInt(value_as_int));
2137 Node* constant = InsertTypeOverrideForVerifier(
2138 NodeProperties::GetType(node),
2139 lowering->jsgraph()->IntPtrConstant(smi));
2140 DeferReplacement(node, constant);
2141 }
2142 return;
2143 }
2144 VisitLeaf<T>(node, MachineRepresentation::kTagged);
2145 return;
2146 }
2147 case IrOpcode::kHeapConstant:
2148 case IrOpcode::kDelayedStringConstant:
2149 return VisitLeaf<T>(node, MachineRepresentation::kTaggedPointer);
2150 case IrOpcode::kPointerConstant: {
2151 VisitLeaf<T>(node, MachineType::PointerRepresentation());
2152 if (lower<T>()) {
2153 intptr_t const value = OpParameter<intptr_t>(node->op());
2154 DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
2155 }
2156 return;
2157 }
2158
2159 case IrOpcode::kBranch: {
2160 DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
2161 ProcessInput<T>(node, 0, UseInfo::Bool());
2162 EnqueueInput<T>(node, NodeProperties::FirstControlIndex(node));
2163 return;
2164 }
2165 case IrOpcode::kSwitch:
2166 ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());
2167 EnqueueInput<T>(node, NodeProperties::FirstControlIndex(node));
2168 return;
2169 case IrOpcode::kSelect:
2170 return VisitSelect<T>(node, truncation, lowering);
2171 case IrOpcode::kPhi:
2172 return VisitPhi<T>(node, truncation, lowering);
2173 case IrOpcode::kCall:
2174 return VisitCall<T>(node, lowering);
2175
2176 //------------------------------------------------------------------
2177 // JavaScript operators.
2178 //------------------------------------------------------------------
2179 case IrOpcode::kJSToNumber:
2180 case IrOpcode::kJSToNumberConvertBigInt:
2181 case IrOpcode::kJSToNumeric: {
2182 DCHECK(NodeProperties::GetType(node).Is(Type::Union(
2183 Type::BigInt(), Type::NumberOrOddball(), graph()->zone())));
2184 VisitInputs<T>(node);
2185 // TODO(bmeurer): Optimize somewhat based on input type?
2186 if (truncation.IsUsedAsWord32()) {
2187 SetOutput<T>(node, MachineRepresentation::kWord32);
2188 if (lower<T>())
2189 lowering->DoJSToNumberOrNumericTruncatesToWord32(node, this);
2190 } else if (truncation.TruncatesOddballAndBigIntToNumber()) {
2191 SetOutput<T>(node, MachineRepresentation::kFloat64);
2192 if (lower<T>())
2193 lowering->DoJSToNumberOrNumericTruncatesToFloat64(node, this);
2194 } else {
2195 SetOutput<T>(node, MachineRepresentation::kTagged);
2196 }
2197 return;
2198 }
2199
2200 //------------------------------------------------------------------
2201 // Simplified operators.
2202 //------------------------------------------------------------------
2203 case IrOpcode::kToBoolean: {
2204 if (truncation.IsUsedAsBool()) {
2205 ProcessInput<T>(node, 0, UseInfo::Bool());
2206 SetOutput<T>(node, MachineRepresentation::kBit);
2207 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2208 } else {
2209 VisitInputs<T>(node);
2210 SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
2211 }
2212 return;
2213 }
2214 case IrOpcode::kBooleanNot: {
2215 if (lower<T>()) {
2216 NodeInfo* input_info = GetInfo(node->InputAt(0));
2217 if (input_info->representation() == MachineRepresentation::kBit) {
2218 // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
2219 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
2220 ChangeOp(node, lowering->machine()->Word32Equal());
2221 } else if (CanBeTaggedPointer(input_info->representation())) {
2222 // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
2223 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
2224 ChangeOp(node, lowering->machine()->WordEqual());
2225 } else {
2226 DCHECK(TypeOf(node->InputAt(0)).IsNone());
2227 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
2228 }
2229 } else {
2230 // No input representation requirement; adapt during lowering.
2231 ProcessInput<T>(node, 0, UseInfo::AnyTruncatingToBool());
2232 SetOutput<T>(node, MachineRepresentation::kBit);
2233 }
2234 return;
2235 }
2236 case IrOpcode::kNumberEqual: {
2237 Type const lhs_type = TypeOf(node->InputAt(0));
2238 Type const rhs_type = TypeOf(node->InputAt(1));
2239 // Regular number comparisons in JavaScript generally identify zeros,
2240 // so we always pass kIdentifyZeros for the inputs, and in addition
2241 // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
2242 // For equality we also handle the case that one side is non-zero, in
2243 // which case we allow to truncate NaN to 0 on the other side.
2244 if ((lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2245 rhs_type.Is(Type::Unsigned32OrMinusZero())) ||
2246 (lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2247 rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2248 OneInputCannotBe(node, type_cache_->kZeroish))) {
2249 // => unsigned Int32Cmp
2250 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2251 MachineRepresentation::kBit);
2252 if (lower<T>()) ChangeOp(node, Uint32Op(node));
2253 return;
2254 }
2255 if ((lhs_type.Is(Type::Signed32OrMinusZero()) &&
2256 rhs_type.Is(Type::Signed32OrMinusZero())) ||
2257 (lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2258 rhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2259 OneInputCannotBe(node, type_cache_->kZeroish))) {
2260 // => signed Int32Cmp
2261 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2262 MachineRepresentation::kBit);
2263 if (lower<T>()) ChangeOp(node, Int32Op(node));
2264 return;
2265 }
2266 // => Float64Cmp
2267 VisitBinop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2268 MachineRepresentation::kBit);
2269 if (lower<T>()) ChangeOp(node, Float64Op(node));
2270 return;
2271 }
2272 case IrOpcode::kNumberLessThan:
2273 case IrOpcode::kNumberLessThanOrEqual: {
2274 Type const lhs_type = TypeOf(node->InputAt(0));
2275 Type const rhs_type = TypeOf(node->InputAt(1));
2276 // Regular number comparisons in JavaScript generally identify zeros,
2277 // so we always pass kIdentifyZeros for the inputs, and in addition
2278 // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
2279 if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2280 rhs_type.Is(Type::Unsigned32OrMinusZero())) {
2281 // => unsigned Int32Cmp
2282 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2283 MachineRepresentation::kBit);
2284 if (lower<T>()) ChangeOp(node, Uint32Op(node));
2285 } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2286 rhs_type.Is(Type::Signed32OrMinusZero())) {
2287 // => signed Int32Cmp
2288 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2289 MachineRepresentation::kBit);
2290 if (lower<T>()) ChangeOp(node, Int32Op(node));
2291 } else {
2292 // => Float64Cmp
2293 VisitBinop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2294 MachineRepresentation::kBit);
2295 if (lower<T>()) ChangeOp(node, Float64Op(node));
2296 }
2297 return;
2298 }
2299
2300 case IrOpcode::kSpeculativeSafeIntegerAdd:
2301 case IrOpcode::kSpeculativeSafeIntegerSubtract:
2302 return VisitSpeculativeIntegerAdditiveOp<T>(node, truncation, lowering);
2303
2304 case IrOpcode::kSpeculativeNumberAdd:
2305 case IrOpcode::kSpeculativeNumberSubtract:
2306 return VisitSpeculativeAdditiveOp<T>(node, truncation, lowering);
2307
2308 case IrOpcode::kSpeculativeNumberLessThan:
2309 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
2310 case IrOpcode::kSpeculativeNumberEqual: {
2311 Type const lhs_type = TypeOf(node->InputAt(0));
2312 Type const rhs_type = TypeOf(node->InputAt(1));
2313 // Regular number comparisons in JavaScript generally identify zeros,
2314 // so we always pass kIdentifyZeros for the inputs, and in addition
2315 // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
2316 if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2317 rhs_type.Is(Type::Unsigned32OrMinusZero())) {
2318 // => unsigned Int32Cmp
2319 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2320 MachineRepresentation::kBit);
2321 if (lower<T>()) ChangeToPureOp(node, Uint32Op(node));
2322 return;
2323 } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2324 rhs_type.Is(Type::Signed32OrMinusZero())) {
2325 // => signed Int32Cmp
2326 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2327 MachineRepresentation::kBit);
2328 if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2329 return;
2330 }
2331 // Try to use type feedback.
2332 NumberOperationHint hint = NumberOperationHintOf(node->op());
2333 switch (hint) {
2334 case NumberOperationHint::kSignedSmall:
2335 if (propagate<T>()) {
2336 VisitBinop<T>(
2337 node, CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2338 MachineRepresentation::kBit);
2339 } else if (retype<T>()) {
2340 SetOutput<T>(node, MachineRepresentation::kBit, Type::Any());
2341 } else {
2342 DCHECK(lower<T>());
2343 Node* lhs = node->InputAt(0);
2344 Node* rhs = node->InputAt(1);
2345 if (IsNodeRepresentationTagged(lhs) &&
2346 IsNodeRepresentationTagged(rhs)) {
2347 VisitBinop<T>(node,
2348 UseInfo::CheckedSignedSmallAsTaggedSigned(
2349 FeedbackSource(), kIdentifyZeros),
2350 MachineRepresentation::kBit);
2351 ChangeToPureOp(
2352 node, changer_->TaggedSignedOperatorFor(node->opcode()));
2353
2354 } else {
2355 VisitBinop<T>(
2356 node, CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2357 MachineRepresentation::kBit);
2358 ChangeToPureOp(node, Int32Op(node));
2359 }
2360 }
2361 return;
2362 case NumberOperationHint::kSignedSmallInputs:
2363 // This doesn't make sense for compare operations.
2364 UNREACHABLE();
2365 case NumberOperationHint::kNumberOrOddball:
2366 // Abstract and strict equality don't perform ToNumber conversions
2367 // on Oddballs, so make sure we don't accidentially sneak in a
2368 // hint with Oddball feedback here.
2369 DCHECK_NE(IrOpcode::kSpeculativeNumberEqual, node->opcode());
2370 V8_FALLTHROUGH;
2371 case NumberOperationHint::kNumberOrBoolean:
2372 case NumberOperationHint::kNumber:
2373 VisitBinop<T>(node,
2374 CheckedUseInfoAsFloat64FromHint(
2375 hint, FeedbackSource(), kIdentifyZeros),
2376 MachineRepresentation::kBit);
2377 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2378 return;
2379 }
2380 UNREACHABLE();
2381 return;
2382 }
2383
2384 case IrOpcode::kNumberAdd:
2385 case IrOpcode::kNumberSubtract: {
2386 if (TypeOf(node->InputAt(0))
2387 .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
2388 TypeOf(node->InputAt(1))
2389 .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
2390 (TypeOf(node).Is(Type::Signed32()) ||
2391 TypeOf(node).Is(Type::Unsigned32()) ||
2392 truncation.IsUsedAsWord32())) {
2393 // => Int32Add/Sub
2394 VisitWord32TruncatingBinop<T>(node);
2395 if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2396 } else if (jsgraph_->machine()->Is64() &&
2397 BothInputsAre(node, type_cache_->kSafeInteger) &&
2398 GetUpperBound(node).Is(type_cache_->kSafeInteger)) {
2399 // => Int64Add/Sub
2400 VisitInt64Binop<T>(node);
2401 if (lower<T>()) ChangeToPureOp(node, Int64Op(node));
2402 } else {
2403 // => Float64Add/Sub
2404 VisitFloat64Binop<T>(node);
2405 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2406 }
2407 return;
2408 }
2409 case IrOpcode::kSpeculativeNumberMultiply: {
2410 if (BothInputsAre(node, Type::Integral32()) &&
2411 (NodeProperties::GetType(node).Is(Type::Signed32()) ||
2412 NodeProperties::GetType(node).Is(Type::Unsigned32()) ||
2413 (truncation.IsUsedAsWord32() &&
2414 NodeProperties::GetType(node).Is(
2415 type_cache_->kSafeIntegerOrMinusZero)))) {
2416 // Multiply reduces to Int32Mul if the inputs are integers, and
2417 // (a) the output is either known to be Signed32, or
2418 // (b) the output is known to be Unsigned32, or
2419 // (c) the uses are truncating and the result is in the safe
2420 // integer range.
2421 VisitWord32TruncatingBinop<T>(node);
2422 if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2423 return;
2424 }
2425 // Try to use type feedback.
2426 NumberOperationHint hint = NumberOperationHintOf(node->op());
2427 Type input0_type = TypeOf(node->InputAt(0));
2428 Type input1_type = TypeOf(node->InputAt(1));
2429
2430 // Handle the case when no int32 checks on inputs are necessary
2431 // (but an overflow check is needed on the output).
2432 if (BothInputsAre(node, Type::Signed32())) {
2433 // If both inputs and feedback are int32, use the overflow op.
2434 if (hint == NumberOperationHint::kSignedSmall) {
2435 VisitForCheckedInt32Mul<T>(node, truncation, input0_type,
2436 input1_type,
2437 UseInfo::TruncatingWord32());
2438 return;
2439 }
2440 }
2441
2442 if (hint == NumberOperationHint::kSignedSmall) {
2443 VisitForCheckedInt32Mul<T>(node, truncation, input0_type, input1_type,
2444 CheckedUseInfoAsWord32FromHint(hint));
2445 return;
2446 }
2447
2448 // Checked float64 x float64 => float64
2449 VisitBinop<T>(node,
2450 UseInfo::CheckedNumberOrOddballAsFloat64(
2451 kDistinguishZeros, FeedbackSource()),
2452 MachineRepresentation::kFloat64, Type::Number());
2453 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2454 return;
2455 }
2456 case IrOpcode::kNumberMultiply: {
2457 if (TypeOf(node->InputAt(0)).Is(Type::Integral32()) &&
2458 TypeOf(node->InputAt(1)).Is(Type::Integral32()) &&
2459 (TypeOf(node).Is(Type::Signed32()) ||
2460 TypeOf(node).Is(Type::Unsigned32()) ||
2461 (truncation.IsUsedAsWord32() &&
2462 TypeOf(node).Is(type_cache_->kSafeIntegerOrMinusZero)))) {
2463 // Multiply reduces to Int32Mul if the inputs are integers, and
2464 // (a) the output is either known to be Signed32, or
2465 // (b) the output is known to be Unsigned32, or
2466 // (c) the uses are truncating and the result is in the safe
2467 // integer range.
2468 VisitWord32TruncatingBinop<T>(node);
2469 if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2470 return;
2471 }
2472 // Number x Number => Float64Mul
2473 VisitFloat64Binop<T>(node);
2474 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2475 return;
2476 }
2477 case IrOpcode::kSpeculativeNumberDivide: {
2478 if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
2479 // => unsigned Uint32Div
2480 VisitWord32TruncatingBinop<T>(node);
2481 if (lower<T>()) DeferReplacement(node, lowering->Uint32Div(node));
2482 return;
2483 }
2484 if (BothInputsAreSigned32(node)) {
2485 if (NodeProperties::GetType(node).Is(Type::Signed32())) {
2486 // => signed Int32Div
2487 VisitWord32TruncatingBinop<T>(node);
2488 if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2489 return;
2490 }
2491 if (truncation.IsUsedAsWord32()) {
2492 // => signed Int32Div
2493 VisitWord32TruncatingBinop<T>(node);
2494 if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2495 return;
2496 }
2497 }
2498
2499 // Try to use type feedback.
2500 NumberOperationHint hint = NumberOperationHintOf(node->op());
2501
2502 // Handle the case when no uint32 checks on inputs are necessary
2503 // (but an overflow check is needed on the output).
2504 if (BothInputsAreUnsigned32(node)) {
2505 if (hint == NumberOperationHint::kSignedSmall) {
2506 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2507 MachineRepresentation::kWord32, Type::Unsigned32());
2508 if (lower<T>()) ChangeToUint32OverflowOp(node);
2509 return;
2510 }
2511 }
2512
2513 // Handle the case when no int32 checks on inputs are necessary
2514 // (but an overflow check is needed on the output).
2515 if (BothInputsAreSigned32(node)) {
2516 // If both the inputs the feedback are int32, use the overflow op.
2517 if (hint == NumberOperationHint::kSignedSmall) {
2518 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2519 MachineRepresentation::kWord32, Type::Signed32());
2520 if (lower<T>()) ChangeToInt32OverflowOp(node);
2521 return;
2522 }
2523 }
2524
2525 if (hint == NumberOperationHint::kSignedSmall ||
2526 hint == NumberOperationHint::kSignedSmallInputs) {
2527 // If the result is truncated, we only need to check the inputs.
2528 if (truncation.IsUsedAsWord32()) {
2529 VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
2530 MachineRepresentation::kWord32);
2531 if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2532 return;
2533 } else if (hint != NumberOperationHint::kSignedSmallInputs) {
2534 VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
2535 MachineRepresentation::kWord32, Type::Signed32());
2536 if (lower<T>()) ChangeToInt32OverflowOp(node);
2537 return;
2538 }
2539 }
2540
2541 // default case => Float64Div
2542 VisitBinop<T>(node,
2543 UseInfo::CheckedNumberOrOddballAsFloat64(
2544 kDistinguishZeros, FeedbackSource()),
2545 MachineRepresentation::kFloat64, Type::Number());
2546 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2547 return;
2548 }
2549 case IrOpcode::kNumberDivide: {
2550 if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
2551 TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
2552 (truncation.IsUsedAsWord32() ||
2553 TypeOf(node).Is(Type::Unsigned32()))) {
2554 // => unsigned Uint32Div
2555 VisitWord32TruncatingBinop<T>(node);
2556 if (lower<T>()) DeferReplacement(node, lowering->Uint32Div(node));
2557 return;
2558 }
2559 if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
2560 TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
2561 (truncation.IsUsedAsWord32() ||
2562 TypeOf(node).Is(Type::Signed32()))) {
2563 // => signed Int32Div
2564 VisitWord32TruncatingBinop<T>(node);
2565 if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2566 return;
2567 }
2568 // Number x Number => Float64Div
2569 VisitFloat64Binop<T>(node);
2570 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2571 return;
2572 }
2573 case IrOpcode::kSpeculativeNumberModulus:
2574 return VisitSpeculativeNumberModulus<T>(node, truncation, lowering);
2575 case IrOpcode::kNumberModulus: {
2576 Type const lhs_type = TypeOf(node->InputAt(0));
2577 Type const rhs_type = TypeOf(node->InputAt(1));
2578 if ((lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
2579 rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) &&
2580 (truncation.IsUsedAsWord32() ||
2581 TypeOf(node).Is(Type::Unsigned32()))) {
2582 // => unsigned Uint32Mod
2583 VisitWord32TruncatingBinop<T>(node);
2584 if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
2585 return;
2586 }
2587 if ((lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
2588 rhs_type.Is(Type::Signed32OrMinusZeroOrNaN())) &&
2589 (truncation.IsUsedAsWord32() || TypeOf(node).Is(Type::Signed32()) ||
2590 (truncation.IdentifiesZeroAndMinusZero() &&
2591 TypeOf(node).Is(Type::Signed32OrMinusZero())))) {
2592 // => signed Int32Mod
2593 VisitWord32TruncatingBinop<T>(node);
2594 if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
2595 return;
2596 }
2597 // => Float64Mod
2598 // For the left hand side we just propagate the identify zeros
2599 // mode of the {truncation}; and for modulus the sign of the
2600 // right hand side doesn't matter anyways, so in particular there's
2601 // no observable difference between a 0 and a -0 then.
2602 UseInfo const lhs_use =
2603 UseInfo::TruncatingFloat64(truncation.identify_zeros());
2604 UseInfo const rhs_use = UseInfo::TruncatingFloat64(kIdentifyZeros);
2605 VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kFloat64);
2606 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2607 return;
2608 }
2609 case IrOpcode::kNumberBitwiseOr:
2610 case IrOpcode::kNumberBitwiseXor:
2611 case IrOpcode::kNumberBitwiseAnd: {
2612 VisitWord32TruncatingBinop<T>(node);
2613 if (lower<T>()) ChangeOp(node, Int32Op(node));
2614 return;
2615 }
2616 case IrOpcode::kSpeculativeNumberBitwiseOr:
2617 case IrOpcode::kSpeculativeNumberBitwiseXor:
2618 case IrOpcode::kSpeculativeNumberBitwiseAnd:
2619 VisitSpeculativeInt32Binop<T>(node);
2620 if (lower<T>()) {
2621 ChangeToPureOp(node, Int32Op(node));
2622 }
2623 return;
2624 case IrOpcode::kNumberShiftLeft: {
2625 Type rhs_type = GetUpperBound(node->InputAt(1));
2626 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2627 UseInfo::TruncatingWord32(),
2628 MachineRepresentation::kWord32);
2629 if (lower<T>()) {
2630 MaskShiftOperand(node, rhs_type);
2631 ChangeToPureOp(node, lowering->machine()->Word32Shl());
2632 }
2633 return;
2634 }
2635 case IrOpcode::kSpeculativeNumberShiftLeft: {
2636 if (BothInputsAre(node, Type::NumberOrOddball())) {
2637 Type rhs_type = GetUpperBound(node->InputAt(1));
2638 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2639 UseInfo::TruncatingWord32(),
2640 MachineRepresentation::kWord32);
2641 if (lower<T>()) {
2642 MaskShiftOperand(node, rhs_type);
2643 ChangeToPureOp(node, lowering->machine()->Word32Shl());
2644 }
2645 return;
2646 }
2647 NumberOperationHint hint = NumberOperationHintOf(node->op());
2648 Type rhs_type = GetUpperBound(node->InputAt(1));
2649 VisitBinop<T>(node,
2650 CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2651 MachineRepresentation::kWord32, Type::Signed32());
2652 if (lower<T>()) {
2653 MaskShiftOperand(node, rhs_type);
2654 ChangeToPureOp(node, lowering->machine()->Word32Shl());
2655 }
2656 return;
2657 }
2658 case IrOpcode::kNumberShiftRight: {
2659 Type rhs_type = GetUpperBound(node->InputAt(1));
2660 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2661 UseInfo::TruncatingWord32(),
2662 MachineRepresentation::kWord32);
2663 if (lower<T>()) {
2664 MaskShiftOperand(node, rhs_type);
2665 ChangeToPureOp(node, lowering->machine()->Word32Sar());
2666 }
2667 return;
2668 }
2669 case IrOpcode::kSpeculativeNumberShiftRight: {
2670 if (BothInputsAre(node, Type::NumberOrOddball())) {
2671 Type rhs_type = GetUpperBound(node->InputAt(1));
2672 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2673 UseInfo::TruncatingWord32(),
2674 MachineRepresentation::kWord32);
2675 if (lower<T>()) {
2676 MaskShiftOperand(node, rhs_type);
2677 ChangeToPureOp(node, lowering->machine()->Word32Sar());
2678 }
2679 return;
2680 }
2681 NumberOperationHint hint = NumberOperationHintOf(node->op());
2682 Type rhs_type = GetUpperBound(node->InputAt(1));
2683 VisitBinop<T>(node,
2684 CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2685 MachineRepresentation::kWord32, Type::Signed32());
2686 if (lower<T>()) {
2687 MaskShiftOperand(node, rhs_type);
2688 ChangeToPureOp(node, lowering->machine()->Word32Sar());
2689 }
2690 return;
2691 }
2692 case IrOpcode::kNumberShiftRightLogical: {
2693 Type rhs_type = GetUpperBound(node->InputAt(1));
2694 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2695 UseInfo::TruncatingWord32(),
2696 MachineRepresentation::kWord32);
2697 if (lower<T>()) {
2698 MaskShiftOperand(node, rhs_type);
2699 ChangeToPureOp(node, lowering->machine()->Word32Shr());
2700 }
2701 return;
2702 }
2703 case IrOpcode::kSpeculativeNumberShiftRightLogical: {
2704 NumberOperationHint hint = NumberOperationHintOf(node->op());
2705 Type rhs_type = GetUpperBound(node->InputAt(1));
2706 if (rhs_type.Is(type_cache_->kZeroish) &&
2707 hint == NumberOperationHint::kSignedSmall &&
2708 !truncation.IsUsedAsWord32()) {
2709 // The SignedSmall or Signed32 feedback means that the results that we
2710 // have seen so far were of type Unsigned31. We speculate that this
2711 // will continue to hold. Moreover, since the RHS is 0, the result
2712 // will just be the (converted) LHS.
2713 VisitBinop<T>(node,
2714 CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2715 MachineRepresentation::kWord32, Type::Unsigned31());
2716 if (lower<T>()) {
2717 node->RemoveInput(1);
2718 ChangeOp(node,
2719 simplified()->CheckedUint32ToInt32(FeedbackSource()));
2720 }
2721 return;
2722 }
2723 if (BothInputsAre(node, Type::NumberOrOddball())) {
2724 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2725 UseInfo::TruncatingWord32(),
2726 MachineRepresentation::kWord32);
2727 if (lower<T>()) {
2728 MaskShiftOperand(node, rhs_type);
2729 ChangeToPureOp(node, lowering->machine()->Word32Shr());
2730 }
2731 return;
2732 }
2733 VisitBinop<T>(node,
2734 CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros),
2735 MachineRepresentation::kWord32, Type::Unsigned32());
2736 if (lower<T>()) {
2737 MaskShiftOperand(node, rhs_type);
2738 ChangeToPureOp(node, lowering->machine()->Word32Shr());
2739 }
2740 return;
2741 }
2742 case IrOpcode::kNumberAbs: {
2743 // NumberAbs maps both 0 and -0 to 0, so we can generally
2744 // pass the kIdentifyZeros truncation to its input, and
2745 // choose to ignore minus zero in all cases.
2746 Type const input_type = TypeOf(node->InputAt(0));
2747 if (input_type.Is(Type::Unsigned32OrMinusZero())) {
2748 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
2749 MachineRepresentation::kWord32);
2750 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2751 } else if (input_type.Is(Type::Signed32OrMinusZero())) {
2752 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
2753 MachineRepresentation::kWord32);
2754 if (lower<T>()) DeferReplacement(node, lowering->Int32Abs(node));
2755 } else if (input_type.Is(type_cache_->kPositiveIntegerOrNaN)) {
2756 VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2757 MachineRepresentation::kFloat64);
2758 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2759 } else {
2760 VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
2761 MachineRepresentation::kFloat64);
2762 if (lower<T>()) ChangeOp(node, Float64Op(node));
2763 }
2764 return;
2765 }
2766 case IrOpcode::kNumberClz32: {
2767 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
2768 MachineRepresentation::kWord32);
2769 if (lower<T>()) ChangeOp(node, Uint32Op(node));
2770 return;
2771 }
2772 case IrOpcode::kNumberImul: {
2773 VisitBinop<T>(node, UseInfo::TruncatingWord32(),
2774 UseInfo::TruncatingWord32(),
2775 MachineRepresentation::kWord32);
2776 if (lower<T>()) ChangeOp(node, Uint32Op(node));
2777 return;
2778 }
2779 case IrOpcode::kNumberFround: {
2780 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
2781 MachineRepresentation::kFloat32);
2782 if (lower<T>()) ChangeOp(node, Float64Op(node));
2783 return;
2784 }
2785 case IrOpcode::kNumberMax: {
2786 // It is safe to use the feedback types for left and right hand side
2787 // here, since we can only narrow those types and thus we can only
2788 // promise a more specific truncation.
2789 // For NumberMax we generally propagate whether the truncation
2790 // identifies zeros to the inputs, and we choose to ignore minus
2791 // zero in those cases.
2792 Type const lhs_type = TypeOf(node->InputAt(0));
2793 Type const rhs_type = TypeOf(node->InputAt(1));
2794 if ((lhs_type.Is(Type::Unsigned32()) &&
2795 rhs_type.Is(Type::Unsigned32())) ||
2796 (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2797 rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2798 truncation.IdentifiesZeroAndMinusZero())) {
2799 VisitWord32TruncatingBinop<T>(node);
2800 if (lower<T>()) {
2801 lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
2802 MachineRepresentation::kWord32);
2803 }
2804 } else if ((lhs_type.Is(Type::Signed32()) &&
2805 rhs_type.Is(Type::Signed32())) ||
2806 (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2807 rhs_type.Is(Type::Signed32OrMinusZero()) &&
2808 truncation.IdentifiesZeroAndMinusZero())) {
2809 VisitWord32TruncatingBinop<T>(node);
2810 if (lower<T>()) {
2811 lowering->DoMax(node, lowering->machine()->Int32LessThan(),
2812 MachineRepresentation::kWord32);
2813 }
2814 } else if (jsgraph_->machine()->Is64() &&
2815 lhs_type.Is(type_cache_->kSafeInteger) &&
2816 rhs_type.Is(type_cache_->kSafeInteger)) {
2817 VisitInt64Binop<T>(node);
2818 if (lower<T>()) {
2819 lowering->DoMax(node, lowering->machine()->Int64LessThan(),
2820 MachineRepresentation::kWord64);
2821 }
2822 } else {
2823 VisitBinop<T>(node,
2824 UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2825 MachineRepresentation::kFloat64);
2826 if (lower<T>()) {
2827 // If the right hand side is not NaN, and the left hand side
2828 // is not NaN (or -0 if the difference between the zeros is
2829 // observed), we can do a simple floating point comparison here.
2830 if (lhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2831 ? Type::OrderedNumber()
2832 : Type::PlainNumber()) &&
2833 rhs_type.Is(Type::OrderedNumber())) {
2834 lowering->DoMax(node, lowering->machine()->Float64LessThan(),
2835 MachineRepresentation::kFloat64);
2836 } else {
2837 ChangeOp(node, Float64Op(node));
2838 }
2839 }
2840 }
2841 return;
2842 }
2843 case IrOpcode::kNumberMin: {
2844 // It is safe to use the feedback types for left and right hand side
2845 // here, since we can only narrow those types and thus we can only
2846 // promise a more specific truncation.
2847 // For NumberMin we generally propagate whether the truncation
2848 // identifies zeros to the inputs, and we choose to ignore minus
2849 // zero in those cases.
2850 Type const lhs_type = TypeOf(node->InputAt(0));
2851 Type const rhs_type = TypeOf(node->InputAt(1));
2852 if ((lhs_type.Is(Type::Unsigned32()) &&
2853 rhs_type.Is(Type::Unsigned32())) ||
2854 (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2855 rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
2856 truncation.IdentifiesZeroAndMinusZero())) {
2857 VisitWord32TruncatingBinop<T>(node);
2858 if (lower<T>()) {
2859 lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
2860 MachineRepresentation::kWord32);
2861 }
2862 } else if ((lhs_type.Is(Type::Signed32()) &&
2863 rhs_type.Is(Type::Signed32())) ||
2864 (lhs_type.Is(Type::Signed32OrMinusZero()) &&
2865 rhs_type.Is(Type::Signed32OrMinusZero()) &&
2866 truncation.IdentifiesZeroAndMinusZero())) {
2867 VisitWord32TruncatingBinop<T>(node);
2868 if (lower<T>()) {
2869 lowering->DoMin(node, lowering->machine()->Int32LessThan(),
2870 MachineRepresentation::kWord32);
2871 }
2872 } else if (jsgraph_->machine()->Is64() &&
2873 lhs_type.Is(type_cache_->kSafeInteger) &&
2874 rhs_type.Is(type_cache_->kSafeInteger)) {
2875 VisitInt64Binop<T>(node);
2876 if (lower<T>()) {
2877 lowering->DoMin(node, lowering->machine()->Int64LessThan(),
2878 MachineRepresentation::kWord64);
2879 }
2880 } else {
2881 VisitBinop<T>(node,
2882 UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2883 MachineRepresentation::kFloat64);
2884 if (lower<T>()) {
2885 // If the left hand side is not NaN, and the right hand side
2886 // is not NaN (or -0 if the difference between the zeros is
2887 // observed), we can do a simple floating point comparison here.
2888 if (lhs_type.Is(Type::OrderedNumber()) &&
2889 rhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
2890 ? Type::OrderedNumber()
2891 : Type::PlainNumber())) {
2892 lowering->DoMin(node,
2893 lowering->machine()->Float64LessThanOrEqual(),
2894 MachineRepresentation::kFloat64);
2895 } else {
2896 ChangeOp(node, Float64Op(node));
2897 }
2898 }
2899 }
2900 return;
2901 }
2902 case IrOpcode::kSpeculativeNumberPow: {
2903 // Checked float64 ** float64 => float64
2904 VisitBinop<T>(node,
2905 UseInfo::CheckedNumberOrOddballAsFloat64(
2906 kDistinguishZeros, FeedbackSource()),
2907 MachineRepresentation::kFloat64, Type::Number());
2908 if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2909 return;
2910 }
2911 case IrOpcode::kNumberAtan2:
2912 case IrOpcode::kNumberPow: {
2913 VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
2914 MachineRepresentation::kFloat64);
2915 if (lower<T>()) ChangeOp(node, Float64Op(node));
2916 return;
2917 }
2918 case IrOpcode::kNumberCeil:
2919 case IrOpcode::kNumberFloor:
2920 case IrOpcode::kNumberRound:
2921 case IrOpcode::kNumberTrunc: {
2922 // For NumberCeil, NumberFloor, NumberRound and NumberTrunc we propagate
2923 // the zero identification part of the truncation, and we turn them into
2924 // no-ops if we figure out (late) that their input is already an
2925 // integer, NaN or -0.
2926 Type const input_type = TypeOf(node->InputAt(0));
2927 VisitUnop<T>(node,
2928 UseInfo::TruncatingFloat64(truncation.identify_zeros()),
2929 MachineRepresentation::kFloat64);
2930 if (lower<T>()) {
2931 if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2932 DeferReplacement(node, node->InputAt(0));
2933 } else if (node->opcode() == IrOpcode::kNumberRound) {
2934 DeferReplacement(node, lowering->Float64Round(node));
2935 } else {
2936 ChangeOp(node, Float64Op(node));
2937 }
2938 }
2939 return;
2940 }
2941 case IrOpcode::kCheckBigInt: {
2942 if (InputIs(node, Type::BigInt())) {
2943 VisitNoop<T>(node, truncation);
2944 } else {
2945 VisitUnop<T>(node, UseInfo::AnyTagged(),
2946 MachineRepresentation::kTaggedPointer);
2947 }
2948 return;
2949 }
2950 case IrOpcode::kSpeculativeBigIntAsIntN:
2951 case IrOpcode::kSpeculativeBigIntAsUintN: {
2952 const bool is_asuintn =
2953 node->opcode() == IrOpcode::kSpeculativeBigIntAsUintN;
2954 const auto p = SpeculativeBigIntAsNParametersOf(node->op());
2955 DCHECK_LE(0, p.bits());
2956 DCHECK_LE(p.bits(), 64);
2957
2958 ProcessInput<T>(node, 0,
2959 UseInfo::CheckedBigIntTruncatingWord64(p.feedback()));
2960 SetOutput<T>(
2961 node, MachineRepresentation::kWord64,
2962 is_asuintn ? Type::UnsignedBigInt64() : Type::SignedBigInt64());
2963 if (lower<T>()) {
2964 if (p.bits() == 0) {
2965 DeferReplacement(
2966 node, InsertTypeOverrideForVerifier(Type::UnsignedBigInt63(),
2967 jsgraph_->ZeroConstant()));
2968 } else if (p.bits() == 64) {
2969 DeferReplacement(node, node->InputAt(0));
2970 } else {
2971 if (is_asuintn) {
2972 const uint64_t mask = (1ULL << p.bits()) - 1ULL;
2973 ChangeUnaryToPureBinaryOp(node, lowering->machine()->Word64And(),
2974 1, jsgraph_->Int64Constant(mask));
2975 } else {
2976 // We truncate the value to N bits, but to correctly interpret
2977 // negative values, we have to fill the top (64-N) bits with the
2978 // sign. This is done by shifting the value left and then back
2979 // with an arithmetic right shift. E.g. for {value} =
2980 // 0..0'0001'1101 (29n) and N = 3: {shifted} is 1010'0000'0..0
2981 // after left shift by 61 bits, {unshifted} is 1..1'1111'1101
2982 // after arithmetic right shift by 61. This is the 64 bit
2983 // representation of -3 we expect for the signed 3 bit integer
2984 // 101.
2985 const uint64_t shift = 64 - p.bits();
2986 Node* value = node->InputAt(0);
2987 Node* shifted =
2988 graph()->NewNode(lowering->machine()->Word64Shl(), value,
2989 jsgraph_->Uint64Constant(shift));
2990 Node* unshifted =
2991 graph()->NewNode(lowering->machine()->Word64Sar(), shifted,
2992 jsgraph_->Uint64Constant(shift));
2993
2994 ReplaceWithPureNode(node, unshifted);
2995 }
2996 }
2997 }
2998 return;
2999 }
3000 case IrOpcode::kNumberAcos:
3001 case IrOpcode::kNumberAcosh:
3002 case IrOpcode::kNumberAsin:
3003 case IrOpcode::kNumberAsinh:
3004 case IrOpcode::kNumberAtan:
3005 case IrOpcode::kNumberAtanh:
3006 case IrOpcode::kNumberCos:
3007 case IrOpcode::kNumberCosh:
3008 case IrOpcode::kNumberExp:
3009 case IrOpcode::kNumberExpm1:
3010 case IrOpcode::kNumberLog:
3011 case IrOpcode::kNumberLog1p:
3012 case IrOpcode::kNumberLog2:
3013 case IrOpcode::kNumberLog10:
3014 case IrOpcode::kNumberCbrt:
3015 case IrOpcode::kNumberSin:
3016 case IrOpcode::kNumberSinh:
3017 case IrOpcode::kNumberTan:
3018 case IrOpcode::kNumberTanh: {
3019 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3020 MachineRepresentation::kFloat64);
3021 if (lower<T>()) ChangeOp(node, Float64Op(node));
3022 return;
3023 }
3024 case IrOpcode::kNumberSign: {
3025 if (InputIs(node, Type::Signed32())) {
3026 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3027 MachineRepresentation::kWord32);
3028 if (lower<T>()) DeferReplacement(node, lowering->Int32Sign(node));
3029 } else {
3030 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3031 MachineRepresentation::kFloat64);
3032 if (lower<T>()) DeferReplacement(node, lowering->Float64Sign(node));
3033 }
3034 return;
3035 }
3036 case IrOpcode::kNumberSilenceNaN: {
3037 Type const input_type = TypeOf(node->InputAt(0));
3038 if (input_type.Is(Type::OrderedNumber())) {
3039 // No need to silence anything if the input cannot be NaN.
3040 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3041 MachineRepresentation::kFloat64);
3042 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3043 } else {
3044 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3045 MachineRepresentation::kFloat64);
3046 if (lower<T>()) ChangeOp(node, Float64Op(node));
3047 }
3048 return;
3049 }
3050 case IrOpcode::kNumberSqrt: {
3051 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3052 MachineRepresentation::kFloat64);
3053 if (lower<T>()) ChangeOp(node, Float64Op(node));
3054 return;
3055 }
3056 case IrOpcode::kNumberToBoolean: {
3057 // For NumberToBoolean we don't care whether the input is 0 or
3058 // -0, since both of them are mapped to false anyways, so we
3059 // can generally pass kIdentifyZeros truncation.
3060 Type const input_type = TypeOf(node->InputAt(0));
3061 if (input_type.Is(Type::Integral32OrMinusZeroOrNaN())) {
3062 // 0, -0 and NaN all map to false, so we can safely truncate
3063 // all of them to zero here.
3064 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3065 MachineRepresentation::kBit);
3066 if (lower<T>()) lowering->DoIntegral32ToBit(node);
3067 } else if (input_type.Is(Type::OrderedNumber())) {
3068 VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
3069 MachineRepresentation::kBit);
3070 if (lower<T>()) lowering->DoOrderedNumberToBit(node);
3071 } else {
3072 VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
3073 MachineRepresentation::kBit);
3074 if (lower<T>()) lowering->DoNumberToBit(node);
3075 }
3076 return;
3077 }
3078 case IrOpcode::kNumberToInt32: {
3079 // Just change representation if necessary.
3080 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3081 MachineRepresentation::kWord32);
3082 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3083 return;
3084 }
3085 case IrOpcode::kNumberToString: {
3086 VisitUnop<T>(node, UseInfo::AnyTagged(),
3087 MachineRepresentation::kTaggedPointer);
3088 return;
3089 }
3090 case IrOpcode::kNumberToUint32: {
3091 // Just change representation if necessary.
3092 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3093 MachineRepresentation::kWord32);
3094 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3095 return;
3096 }
3097 case IrOpcode::kNumberToUint8Clamped: {
3098 Type const input_type = TypeOf(node->InputAt(0));
3099 if (input_type.Is(type_cache_->kUint8OrMinusZeroOrNaN)) {
3100 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3101 MachineRepresentation::kWord32);
3102 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3103 } else if (input_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) {
3104 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3105 MachineRepresentation::kWord32);
3106 if (lower<T>()) lowering->DoUnsigned32ToUint8Clamped(node);
3107 } else if (input_type.Is(Type::Signed32OrMinusZeroOrNaN())) {
3108 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3109 MachineRepresentation::kWord32);
3110 if (lower<T>()) lowering->DoSigned32ToUint8Clamped(node);
3111 } else if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
3112 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3113 MachineRepresentation::kFloat64);
3114 if (lower<T>()) lowering->DoIntegerToUint8Clamped(node);
3115 } else {
3116 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3117 MachineRepresentation::kFloat64);
3118 if (lower<T>()) lowering->DoNumberToUint8Clamped(node);
3119 }
3120 return;
3121 }
3122 case IrOpcode::kReferenceEqual: {
3123 VisitBinop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3124 if (lower<T>()) {
3125 if (COMPRESS_POINTERS_BOOL) {
3126 ChangeOp(node, lowering->machine()->Word32Equal());
3127 } else {
3128 ChangeOp(node, lowering->machine()->WordEqual());
3129 }
3130 }
3131 return;
3132 }
3133 case IrOpcode::kSameValueNumbersOnly: {
3134 VisitBinop<T>(node, UseInfo::AnyTagged(),
3135 MachineRepresentation::kTaggedPointer);
3136 return;
3137 }
3138 case IrOpcode::kSameValue: {
3139 if (truncation.IsUnused()) return VisitUnused<T>(node);
3140 if (BothInputsAre(node, Type::Number())) {
3141 VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
3142 MachineRepresentation::kBit);
3143 if (lower<T>()) {
3144 ChangeOp(node, lowering->simplified()->NumberSameValue());
3145 }
3146 } else {
3147 VisitBinop<T>(node, UseInfo::AnyTagged(),
3148 MachineRepresentation::kTaggedPointer);
3149 }
3150 return;
3151 }
3152 case IrOpcode::kTypeOf: {
3153 return VisitUnop<T>(node, UseInfo::AnyTagged(),
3154 MachineRepresentation::kTaggedPointer);
3155 }
3156 case IrOpcode::kNewConsString: {
3157 ProcessInput<T>(node, 0, UseInfo::TruncatingWord32()); // length
3158 ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // first
3159 ProcessInput<T>(node, 2, UseInfo::AnyTagged()); // second
3160 SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3161 return;
3162 }
3163 case IrOpcode::kSpeculativeBigIntAdd: {
3164 // TODO(nicohartmann@, chromium:1073440): There should be special
3165 // handling for trunction.IsUnused() that correctly propagates deadness,
3166 // but preserves type checking which may throw exceptions. Until this
3167 // is fully supported, we lower to int64 operations but keep pushing
3168 // type constraints.
3169 if (truncation.IsUsedAsWord64()) {
3170 VisitBinop<T>(
3171 node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
3172 MachineRepresentation::kWord64);
3173 if (lower<T>()) {
3174 ChangeToPureOp(node, lowering->machine()->Int64Add());
3175 }
3176 } else {
3177 VisitBinop<T>(node,
3178 UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
3179 MachineRepresentation::kTaggedPointer);
3180 if (lower<T>()) {
3181 ChangeOp(node, lowering->simplified()->BigIntAdd());
3182 }
3183 }
3184 return;
3185 }
3186 case IrOpcode::kSpeculativeBigIntSubtract: {
3187 if (truncation.IsUsedAsWord64()) {
3188 VisitBinop<T>(
3189 node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
3190 MachineRepresentation::kWord64);
3191 if (lower<T>()) {
3192 ChangeToPureOp(node, lowering->machine()->Int64Sub());
3193 }
3194 } else {
3195 VisitBinop<T>(node,
3196 UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
3197 MachineRepresentation::kTaggedPointer);
3198 if (lower<T>()) {
3199 ChangeOp(node, lowering->simplified()->BigIntSubtract());
3200 }
3201 }
3202 return;
3203 }
3204 case IrOpcode::kSpeculativeBigIntNegate: {
3205 if (truncation.IsUsedAsWord64()) {
3206 VisitUnop<T>(node,
3207 UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
3208 MachineRepresentation::kWord64);
3209 if (lower<T>()) {
3210 ChangeUnaryToPureBinaryOp(node, lowering->machine()->Int64Sub(), 0,
3211 jsgraph_->Int64Constant(0));
3212 }
3213 } else {
3214 VisitUnop<T>(node,
3215 UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
3216 MachineRepresentation::kTaggedPointer);
3217 if (lower<T>()) {
3218 ChangeToPureOp(node, lowering->simplified()->BigIntNegate());
3219 }
3220 }
3221 return;
3222 }
3223 case IrOpcode::kStringConcat: {
3224 // TODO(turbofan): We currently depend on having this first length input
3225 // to make sure that the overflow check is properly scheduled before the
3226 // actual string concatenation. We should also use the length to pass it
3227 // to the builtin or decide in optimized code how to construct the
3228 // resulting string (i.e. cons string or sequential string).
3229 ProcessInput<T>(node, 0, UseInfo::TaggedSigned()); // length
3230 ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // first
3231 ProcessInput<T>(node, 2, UseInfo::AnyTagged()); // second
3232 SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3233 return;
3234 }
3235 case IrOpcode::kStringEqual:
3236 case IrOpcode::kStringLessThan:
3237 case IrOpcode::kStringLessThanOrEqual: {
3238 return VisitBinop<T>(node, UseInfo::AnyTagged(),
3239 MachineRepresentation::kTaggedPointer);
3240 }
3241 case IrOpcode::kStringCharCodeAt: {
3242 return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
3243 MachineRepresentation::kWord32);
3244 }
3245 case IrOpcode::kStringCodePointAt: {
3246 return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
3247 MachineRepresentation::kWord32);
3248 }
3249 case IrOpcode::kStringFromSingleCharCode: {
3250 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3251 MachineRepresentation::kTaggedPointer);
3252 return;
3253 }
3254 case IrOpcode::kStringFromSingleCodePoint: {
3255 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3256 MachineRepresentation::kTaggedPointer);
3257 return;
3258 }
3259 case IrOpcode::kStringFromCodePointAt: {
3260 return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
3261 MachineRepresentation::kTaggedPointer);
3262 }
3263 case IrOpcode::kStringIndexOf: {
3264 ProcessInput<T>(node, 0, UseInfo::AnyTagged());
3265 ProcessInput<T>(node, 1, UseInfo::AnyTagged());
3266 ProcessInput<T>(node, 2, UseInfo::TaggedSigned());
3267 SetOutput<T>(node, MachineRepresentation::kTaggedSigned);
3268 return;
3269 }
3270 case IrOpcode::kStringLength: {
3271 // TODO(bmeurer): The input representation should be TaggedPointer.
3272 // Fix this once we have a dedicated StringConcat/JSStringAdd
3273 // operator, which marks it's output as TaggedPointer properly.
3274 VisitUnop<T>(node, UseInfo::AnyTagged(),
3275 MachineRepresentation::kWord32);
3276 return;
3277 }
3278 case IrOpcode::kStringSubstring: {
3279 ProcessInput<T>(node, 0, UseInfo::AnyTagged());
3280 ProcessInput<T>(node, 1, UseInfo::TruncatingWord32());
3281 ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());
3282 ProcessRemainingInputs<T>(node, 3);
3283 SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3284 return;
3285 }
3286 case IrOpcode::kStringToLowerCaseIntl:
3287 case IrOpcode::kStringToUpperCaseIntl: {
3288 VisitUnop<T>(node, UseInfo::AnyTagged(),
3289 MachineRepresentation::kTaggedPointer);
3290 return;
3291 }
3292 case IrOpcode::kCheckBounds:
3293 return VisitCheckBounds<T>(node, lowering);
3294 case IrOpcode::kCheckHeapObject: {
3295 if (InputCannotBe(node, Type::SignedSmall())) {
3296 VisitUnop<T>(node, UseInfo::AnyTagged(),
3297 MachineRepresentation::kTaggedPointer);
3298 } else {
3299 VisitUnop<T>(
3300 node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3301 MachineRepresentation::kTaggedPointer);
3302 }
3303 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3304 return;
3305 }
3306 case IrOpcode::kCheckIf: {
3307 ProcessInput<T>(node, 0, UseInfo::Bool());
3308 ProcessRemainingInputs<T>(node, 1);
3309 SetOutput<T>(node, MachineRepresentation::kNone);
3310 return;
3311 }
3312 case IrOpcode::kCheckInternalizedString: {
3313 VisitCheck<T>(node, Type::InternalizedString(), lowering);
3314 return;
3315 }
3316 case IrOpcode::kCheckNumber: {
3317 Type const input_type = TypeOf(node->InputAt(0));
3318 if (input_type.Is(Type::Number())) {
3319 VisitNoop<T>(node, truncation);
3320 } else {
3321 VisitUnop<T>(node, UseInfo::AnyTagged(),
3322 MachineRepresentation::kTagged);
3323 }
3324 return;
3325 }
3326 case IrOpcode::kCheckReceiver: {
3327 VisitCheck<T>(node, Type::Receiver(), lowering);
3328 return;
3329 }
3330 case IrOpcode::kCheckReceiverOrNullOrUndefined: {
3331 VisitCheck<T>(node, Type::ReceiverOrNullOrUndefined(), lowering);
3332 return;
3333 }
3334 case IrOpcode::kCheckSmi: {
3335 const CheckParameters& params = CheckParametersOf(node->op());
3336 if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
3337 VisitUnop<T>(node,
3338 UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros,
3339 params.feedback()),
3340 MachineRepresentation::kWord32);
3341 } else {
3342 VisitUnop<T>(
3343 node,
3344 UseInfo::CheckedSignedSmallAsTaggedSigned(params.feedback()),
3345 MachineRepresentation::kTaggedSigned);
3346 }
3347 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3348 return;
3349 }
3350 case IrOpcode::kCheckString: {
3351 const CheckParameters& params = CheckParametersOf(node->op());
3352 if (InputIs(node, Type::String())) {
3353 VisitUnop<T>(node, UseInfo::AnyTagged(),
3354 MachineRepresentation::kTaggedPointer);
3355 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3356 } else {
3357 VisitUnop<T>(
3358 node,
3359 UseInfo::CheckedHeapObjectAsTaggedPointer(params.feedback()),
3360 MachineRepresentation::kTaggedPointer);
3361 }
3362 return;
3363 }
3364 case IrOpcode::kCheckSymbol: {
3365 VisitCheck<T>(node, Type::Symbol(), lowering);
3366 return;
3367 }
3368
3369 case IrOpcode::kAllocate: {
3370 ProcessInput<T>(node, 0, UseInfo::Word());
3371 ProcessRemainingInputs<T>(node, 1);
3372 SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3373 return;
3374 }
3375 case IrOpcode::kLoadFramePointer: {
3376 SetOutput<T>(node, MachineType::PointerRepresentation());
3377 return;
3378 }
3379 case IrOpcode::kLoadMessage: {
3380 if (truncation.IsUnused()) return VisitUnused<T>(node);
3381 VisitUnop<T>(node, UseInfo::Word(), MachineRepresentation::kTagged);
3382 return;
3383 }
3384 case IrOpcode::kStoreMessage: {
3385 ProcessInput<T>(node, 0, UseInfo::Word());
3386 ProcessInput<T>(node, 1, UseInfo::AnyTagged());
3387 ProcessRemainingInputs<T>(node, 2);
3388 SetOutput<T>(node, MachineRepresentation::kNone);
3389 return;
3390 }
3391 case IrOpcode::kLoadFieldByIndex: {
3392 if (truncation.IsUnused()) return VisitUnused<T>(node);
3393 VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
3394 MachineRepresentation::kTagged);
3395 return;
3396 }
3397 case IrOpcode::kLoadField: {
3398 if (truncation.IsUnused()) return VisitUnused<T>(node);
3399 FieldAccess access = FieldAccessOf(node->op());
3400 MachineRepresentation const representation =
3401 access.machine_type.representation();
3402 VisitUnop<T>(node, UseInfoForBasePointer(access), representation);
3403 return;
3404 }
3405 case IrOpcode::kStoreField: {
3406 FieldAccess access = FieldAccessOf(node->op());
3407 Node* value_node = node->InputAt(1);
3408 NodeInfo* input_info = GetInfo(value_node);
3409 MachineRepresentation field_representation =
3410 access.machine_type.representation();
3411
3412 // Convert to Smi if possible, such that we can avoid a write barrier.
3413 if (field_representation == MachineRepresentation::kTagged &&
3414 TypeOf(value_node).Is(Type::SignedSmall())) {
3415 field_representation = MachineRepresentation::kTaggedSigned;
3416 }
3417 WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
3418 access.base_is_tagged, field_representation, access.offset,
3419 access.type, input_info->representation(), value_node);
3420
3421 ProcessInput<T>(node, 0, UseInfoForBasePointer(access));
3422 ProcessInput<T>(
3423 node, 1, TruncatingUseInfoFromRepresentation(field_representation));
3424 ProcessRemainingInputs<T>(node, 2);
3425 SetOutput<T>(node, MachineRepresentation::kNone);
3426 if (lower<T>()) {
3427 if (write_barrier_kind < access.write_barrier_kind) {
3428 access.write_barrier_kind = write_barrier_kind;
3429 ChangeOp(node, jsgraph_->simplified()->StoreField(access));
3430 }
3431 }
3432 return;
3433 }
3434 case IrOpcode::kLoadElement: {
3435 if (truncation.IsUnused()) return VisitUnused<T>(node);
3436 ElementAccess access = ElementAccessOf(node->op());
3437 VisitBinop<T>(node, UseInfoForBasePointer(access), UseInfo::Word(),
3438 access.machine_type.representation());
3439 return;
3440 }
3441 case IrOpcode::kLoadStackArgument: {
3442 if (truncation.IsUnused()) return VisitUnused<T>(node);
3443 VisitBinop<T>(node, UseInfo::Word(), MachineRepresentation::kTagged);
3444 return;
3445 }
3446 case IrOpcode::kStoreElement: {
3447 ElementAccess access = ElementAccessOf(node->op());
3448 Node* value_node = node->InputAt(2);
3449 NodeInfo* input_info = GetInfo(value_node);
3450 MachineRepresentation element_representation =
3451 access.machine_type.representation();
3452
3453 // Convert to Smi if possible, such that we can avoid a write barrier.
3454 if (element_representation == MachineRepresentation::kTagged &&
3455 TypeOf(value_node).Is(Type::SignedSmall())) {
3456 element_representation = MachineRepresentation::kTaggedSigned;
3457 }
3458 WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
3459 access.base_is_tagged, element_representation, access.type,
3460 input_info->representation(), value_node);
3461 ProcessInput<T>(node, 0, UseInfoForBasePointer(access)); // base
3462 ProcessInput<T>(node, 1, UseInfo::Word()); // index
3463 ProcessInput<T>(node, 2,
3464 TruncatingUseInfoFromRepresentation(
3465 element_representation)); // value
3466 ProcessRemainingInputs<T>(node, 3);
3467 SetOutput<T>(node, MachineRepresentation::kNone);
3468 if (lower<T>()) {
3469 if (write_barrier_kind < access.write_barrier_kind) {
3470 access.write_barrier_kind = write_barrier_kind;
3471 ChangeOp(node, jsgraph_->simplified()->StoreElement(access));
3472 }
3473 }
3474 return;
3475 }
3476 case IrOpcode::kNumberIsFloat64Hole: {
3477 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3478 MachineRepresentation::kBit);
3479 return;
3480 }
3481 case IrOpcode::kTransitionAndStoreElement: {
3482 Type value_type = TypeOf(node->InputAt(2));
3483
3484 ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // array
3485 ProcessInput<T>(node, 1, UseInfo::Word()); // index
3486
3487 if (value_type.Is(Type::SignedSmall())) {
3488 ProcessInput<T>(node, 2, UseInfo::TruncatingWord32()); // value
3489 if (lower<T>()) {
3490 ChangeOp(node, simplified()->StoreSignedSmallElement());
3491 }
3492 } else if (value_type.Is(Type::Number())) {
3493 ProcessInput<T>(node, 2, UseInfo::TruncatingFloat64()); // value
3494 if (lower<T>()) {
3495 Handle<Map> double_map = DoubleMapParameterOf(node->op());
3496 ChangeOp(node,
3497 simplified()->TransitionAndStoreNumberElement(double_map));
3498 }
3499 } else if (value_type.Is(Type::NonNumber())) {
3500 ProcessInput<T>(node, 2, UseInfo::AnyTagged()); // value
3501 if (lower<T>()) {
3502 Handle<Map> fast_map = FastMapParameterOf(node->op());
3503 ChangeOp(node, simplified()->TransitionAndStoreNonNumberElement(
3504 fast_map, value_type));
3505 }
3506 } else {
3507 ProcessInput<T>(node, 2, UseInfo::AnyTagged()); // value
3508 }
3509
3510 ProcessRemainingInputs<T>(node, 3);
3511 SetOutput<T>(node, MachineRepresentation::kNone);
3512 return;
3513 }
3514 case IrOpcode::kLoadTypedElement: {
3515 MachineRepresentation const rep =
3516 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3517 ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // buffer
3518 ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // base pointer
3519 ProcessInput<T>(node, 2, UseInfo::Word()); // external pointer
3520 ProcessInput<T>(node, 3, UseInfo::Word()); // index
3521 ProcessRemainingInputs<T>(node, 4);
3522 SetOutput<T>(node, rep);
3523 return;
3524 }
3525 case IrOpcode::kLoadDataViewElement: {
3526 MachineRepresentation const rep =
3527 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3528 ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // object
3529 ProcessInput<T>(node, 1, UseInfo::Word()); // base
3530 ProcessInput<T>(node, 2, UseInfo::Word()); // index
3531 ProcessInput<T>(node, 3, UseInfo::Bool()); // little-endian
3532 ProcessRemainingInputs<T>(node, 4);
3533 SetOutput<T>(node, rep);
3534 return;
3535 }
3536 case IrOpcode::kStoreTypedElement: {
3537 MachineRepresentation const rep =
3538 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3539 ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // buffer
3540 ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // base pointer
3541 ProcessInput<T>(node, 2, UseInfo::Word()); // external pointer
3542 ProcessInput<T>(node, 3, UseInfo::Word()); // index
3543 ProcessInput<T>(node, 4,
3544 TruncatingUseInfoFromRepresentation(rep)); // value
3545 ProcessRemainingInputs<T>(node, 5);
3546 SetOutput<T>(node, MachineRepresentation::kNone);
3547 return;
3548 }
3549 case IrOpcode::kStoreDataViewElement: {
3550 MachineRepresentation const rep =
3551 MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3552 ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // object
3553 ProcessInput<T>(node, 1, UseInfo::Word()); // base
3554 ProcessInput<T>(node, 2, UseInfo::Word()); // index
3555 ProcessInput<T>(node, 3,
3556 TruncatingUseInfoFromRepresentation(rep)); // value
3557 ProcessInput<T>(node, 4, UseInfo::Bool()); // little-endian
3558 ProcessRemainingInputs<T>(node, 5);
3559 SetOutput<T>(node, MachineRepresentation::kNone);
3560 return;
3561 }
3562 case IrOpcode::kConvertReceiver: {
3563 Type input_type = TypeOf(node->InputAt(0));
3564 VisitBinop<T>(node, UseInfo::AnyTagged(),
3565 MachineRepresentation::kTaggedPointer);
3566 if (lower<T>()) {
3567 // Try to optimize the {node} based on the input type.
3568 if (input_type.Is(Type::Receiver())) {
3569 DeferReplacement(node, node->InputAt(0));
3570 } else if (input_type.Is(Type::NullOrUndefined())) {
3571 DeferReplacement(node, node->InputAt(1));
3572 } else if (!input_type.Maybe(Type::NullOrUndefined())) {
3573 ChangeOp(node, lowering->simplified()->ConvertReceiver(
3574 ConvertReceiverMode::kNotNullOrUndefined));
3575 }
3576 }
3577 return;
3578 }
3579 case IrOpcode::kPlainPrimitiveToNumber: {
3580 if (InputIs(node, Type::Boolean())) {
3581 VisitUnop<T>(node, UseInfo::Bool(), MachineRepresentation::kWord32);
3582 if (lower<T>()) {
3583 ChangeToSemanticsHintForVerifier(node, node->op());
3584 }
3585 } else if (InputIs(node, Type::String())) {
3586 VisitUnop<T>(node, UseInfo::AnyTagged(),
3587 MachineRepresentation::kTagged);
3588 if (lower<T>()) {
3589 ChangeOp(node, simplified()->StringToNumber());
3590 }
3591 } else if (truncation.IsUsedAsWord32()) {
3592 if (InputIs(node, Type::NumberOrOddball())) {
3593 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3594 MachineRepresentation::kWord32);
3595 if (lower<T>()) {
3596 ChangeToSemanticsHintForVerifier(node, node->op());
3597 }
3598 } else {
3599 VisitUnop<T>(node, UseInfo::AnyTagged(),
3600 MachineRepresentation::kWord32);
3601 if (lower<T>()) {
3602 ChangeOp(node, simplified()->PlainPrimitiveToWord32());
3603 }
3604 }
3605 } else if (truncation.TruncatesOddballAndBigIntToNumber()) {
3606 if (InputIs(node, Type::NumberOrOddball())) {
3607 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3608 MachineRepresentation::kFloat64);
3609 if (lower<T>()) {
3610 ChangeToSemanticsHintForVerifier(node, node->op());
3611 }
3612 } else {
3613 VisitUnop<T>(node, UseInfo::AnyTagged(),
3614 MachineRepresentation::kFloat64);
3615 if (lower<T>()) {
3616 ChangeOp(node, simplified()->PlainPrimitiveToFloat64());
3617 }
3618 }
3619 } else {
3620 VisitUnop<T>(node, UseInfo::AnyTagged(),
3621 MachineRepresentation::kTagged);
3622 }
3623 return;
3624 }
3625 case IrOpcode::kSpeculativeToNumber: {
3626 NumberOperationParameters const& p =
3627 NumberOperationParametersOf(node->op());
3628 switch (p.hint()) {
3629 case NumberOperationHint::kSignedSmall:
3630 case NumberOperationHint::kSignedSmallInputs:
3631 VisitUnop<T>(node,
3632 CheckedUseInfoAsWord32FromHint(
3633 p.hint(), kDistinguishZeros, p.feedback()),
3634 MachineRepresentation::kWord32, Type::Signed32());
3635 break;
3636 case NumberOperationHint::kNumber:
3637 case NumberOperationHint::kNumberOrBoolean:
3638 case NumberOperationHint::kNumberOrOddball:
3639 VisitUnop<T>(
3640 node, CheckedUseInfoAsFloat64FromHint(p.hint(), p.feedback()),
3641 MachineRepresentation::kFloat64);
3642 break;
3643 }
3644 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3645 return;
3646 }
3647 case IrOpcode::kObjectIsArrayBufferView: {
3648 // TODO(turbofan): Introduce a Type::ArrayBufferView?
3649 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3650 return;
3651 }
3652 case IrOpcode::kObjectIsBigInt: {
3653 VisitObjectIs<T>(node, Type::BigInt(), lowering);
3654 return;
3655 }
3656 case IrOpcode::kObjectIsCallable: {
3657 VisitObjectIs<T>(node, Type::Callable(), lowering);
3658 return;
3659 }
3660 case IrOpcode::kObjectIsConstructor: {
3661 // TODO(turbofan): Introduce a Type::Constructor?
3662 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3663 return;
3664 }
3665 case IrOpcode::kObjectIsDetectableCallable: {
3666 VisitObjectIs<T>(node, Type::DetectableCallable(), lowering);
3667 return;
3668 }
3669 case IrOpcode::kObjectIsFiniteNumber: {
3670 Type const input_type = GetUpperBound(node->InputAt(0));
3671 if (input_type.Is(type_cache_->kSafeInteger)) {
3672 VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3673 if (lower<T>()) {
3674 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3675 }
3676 } else if (!input_type.Maybe(Type::Number())) {
3677 VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3678 if (lower<T>()) {
3679 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3680 }
3681 } else if (input_type.Is(Type::Number())) {
3682 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3683 MachineRepresentation::kBit);
3684 if (lower<T>()) {
3685 ChangeOp(node, lowering->simplified()->NumberIsFinite());
3686 }
3687 } else {
3688 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3689 }
3690 return;
3691 }
3692 case IrOpcode::kNumberIsFinite: {
3693 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3694 MachineRepresentation::kBit);
3695 return;
3696 }
3697 case IrOpcode::kObjectIsSafeInteger: {
3698 Type const input_type = GetUpperBound(node->InputAt(0));
3699 if (input_type.Is(type_cache_->kSafeInteger)) {
3700 VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3701 if (lower<T>()) {
3702 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3703 }
3704 } else if (!input_type.Maybe(Type::Number())) {
3705 VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3706 if (lower<T>()) {
3707 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3708 }
3709 } else if (input_type.Is(Type::Number())) {
3710 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3711 MachineRepresentation::kBit);
3712 if (lower<T>()) {
3713 ChangeOp(node, lowering->simplified()->NumberIsSafeInteger());
3714 }
3715 } else {
3716 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3717 }
3718 return;
3719 }
3720 case IrOpcode::kNumberIsSafeInteger: {
3721 UNREACHABLE();
3722 }
3723 case IrOpcode::kObjectIsInteger: {
3724 Type const input_type = GetUpperBound(node->InputAt(0));
3725 if (input_type.Is(type_cache_->kSafeInteger)) {
3726 VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3727 if (lower<T>()) {
3728 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3729 }
3730 } else if (!input_type.Maybe(Type::Number())) {
3731 VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3732 if (lower<T>()) {
3733 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3734 }
3735 } else if (input_type.Is(Type::Number())) {
3736 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3737 MachineRepresentation::kBit);
3738 if (lower<T>()) {
3739 ChangeOp(node, lowering->simplified()->NumberIsInteger());
3740 }
3741 } else {
3742 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3743 }
3744 return;
3745 }
3746 case IrOpcode::kNumberIsInteger: {
3747 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3748 MachineRepresentation::kBit);
3749 return;
3750 }
3751 case IrOpcode::kObjectIsMinusZero: {
3752 Type const input_type = GetUpperBound(node->InputAt(0));
3753 if (input_type.Is(Type::MinusZero())) {
3754 VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3755 if (lower<T>()) {
3756 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3757 }
3758 } else if (!input_type.Maybe(Type::MinusZero())) {
3759 VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3760 if (lower<T>()) {
3761 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3762 }
3763 } else if (input_type.Is(Type::Number())) {
3764 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3765 MachineRepresentation::kBit);
3766 if (lower<T>()) {
3767 ChangeOp(node, simplified()->NumberIsMinusZero());
3768 }
3769 } else {
3770 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3771 }
3772 return;
3773 }
3774 case IrOpcode::kObjectIsNaN: {
3775 Type const input_type = GetUpperBound(node->InputAt(0));
3776 if (input_type.Is(Type::NaN())) {
3777 VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3778 if (lower<T>()) {
3779 DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
3780 }
3781 } else if (!input_type.Maybe(Type::NaN())) {
3782 VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3783 if (lower<T>()) {
3784 DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
3785 }
3786 } else if (input_type.Is(Type::Number())) {
3787 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3788 MachineRepresentation::kBit);
3789 if (lower<T>()) {
3790 ChangeOp(node, simplified()->NumberIsNaN());
3791 }
3792 } else {
3793 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3794 }
3795 return;
3796 }
3797 case IrOpcode::kNumberIsNaN: {
3798 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3799 MachineRepresentation::kBit);
3800 return;
3801 }
3802 case IrOpcode::kObjectIsNonCallable: {
3803 VisitObjectIs<T>(node, Type::NonCallable(), lowering);
3804 return;
3805 }
3806 case IrOpcode::kObjectIsNumber: {
3807 VisitObjectIs<T>(node, Type::Number(), lowering);
3808 return;
3809 }
3810 case IrOpcode::kObjectIsReceiver: {
3811 VisitObjectIs<T>(node, Type::Receiver(), lowering);
3812 return;
3813 }
3814 case IrOpcode::kObjectIsSmi: {
3815 // TODO(turbofan): Optimize based on input representation.
3816 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3817 return;
3818 }
3819 case IrOpcode::kObjectIsString: {
3820 VisitObjectIs<T>(node, Type::String(), lowering);
3821 return;
3822 }
3823 case IrOpcode::kObjectIsSymbol: {
3824 VisitObjectIs<T>(node, Type::Symbol(), lowering);
3825 return;
3826 }
3827 case IrOpcode::kObjectIsUndetectable: {
3828 VisitObjectIs<T>(node, Type::Undetectable(), lowering);
3829 return;
3830 }
3831 case IrOpcode::kArgumentsLength:
3832 case IrOpcode::kRestLength: {
3833 SetOutput<T>(node, MachineRepresentation::kTaggedSigned);
3834 return;
3835 }
3836 case IrOpcode::kNewDoubleElements:
3837 case IrOpcode::kNewSmiOrObjectElements: {
3838 VisitUnop<T>(node, UseInfo::Word(),
3839 MachineRepresentation::kTaggedPointer);
3840 return;
3841 }
3842 case IrOpcode::kNewArgumentsElements: {
3843 VisitUnop<T>(node, UseInfo::TaggedSigned(),
3844 MachineRepresentation::kTaggedPointer);
3845 return;
3846 }
3847 case IrOpcode::kCheckFloat64Hole: {
3848 Type const input_type = TypeOf(node->InputAt(0));
3849 CheckFloat64HoleMode mode =
3850 CheckFloat64HoleParametersOf(node->op()).mode();
3851 if (mode == CheckFloat64HoleMode::kAllowReturnHole) {
3852 // If {mode} is allow-return-hole _and_ the {truncation}
3853 // identifies NaN and undefined, we can just pass along
3854 // the {truncation} and completely wipe the {node}.
3855 if (truncation.IsUnused()) return VisitUnused<T>(node);
3856 if (truncation.TruncatesOddballAndBigIntToNumber()) {
3857 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3858 MachineRepresentation::kFloat64);
3859 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3860 return;
3861 }
3862 }
3863 VisitUnop<T>(
3864 node, UseInfo(MachineRepresentation::kFloat64, Truncation::Any()),
3865 MachineRepresentation::kFloat64, Type::Number());
3866 if (lower<T>() && input_type.Is(Type::Number())) {
3867 DeferReplacement(node, node->InputAt(0));
3868 }
3869 return;
3870 }
3871 case IrOpcode::kCheckNotTaggedHole: {
3872 VisitUnop<T>(node, UseInfo::AnyTagged(),
3873 MachineRepresentation::kTagged);
3874 return;
3875 }
3876 case IrOpcode::kCheckClosure: {
3877 VisitUnop<T>(
3878 node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3879 MachineRepresentation::kTaggedPointer);
3880 return;
3881 }
3882 case IrOpcode::kConvertTaggedHoleToUndefined: {
3883 if (InputIs(node, Type::NumberOrOddball()) &&
3884 truncation.IsUsedAsWord32()) {
3885 // Propagate the Word32 truncation.
3886 VisitUnop<T>(node, UseInfo::TruncatingWord32(),
3887 MachineRepresentation::kWord32);
3888 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3889 } else if (InputIs(node, Type::NumberOrOddball()) &&
3890 truncation.TruncatesOddballAndBigIntToNumber()) {
3891 // Propagate the Float64 truncation.
3892 VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
3893 MachineRepresentation::kFloat64);
3894 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3895 } else if (InputIs(node, Type::NonInternal())) {
3896 VisitUnop<T>(node, UseInfo::AnyTagged(),
3897 MachineRepresentation::kTagged);
3898 if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3899 } else {
3900 // TODO(turbofan): Add a (Tagged) truncation that identifies hole
3901 // and undefined, i.e. for a[i] === obj cases.
3902 VisitUnop<T>(node, UseInfo::AnyTagged(),
3903 MachineRepresentation::kTagged);
3904 }
3905 return;
3906 }
3907 case IrOpcode::kCheckEqualsSymbol:
3908 case IrOpcode::kCheckEqualsInternalizedString:
3909 return VisitBinop<T>(node, UseInfo::AnyTagged(),
3910 MachineRepresentation::kNone);
3911 case IrOpcode::kMapGuard:
3912 // Eliminate MapGuard nodes here.
3913 return VisitUnused<T>(node);
3914 case IrOpcode::kCheckMaps: {
3915 CheckMapsParameters const& p = CheckMapsParametersOf(node->op());
3916 return VisitUnop<T>(
3917 node, UseInfo::CheckedHeapObjectAsTaggedPointer(p.feedback()),
3918 MachineRepresentation::kNone);
3919 }
3920 case IrOpcode::kTransitionElementsKind: {
3921 return VisitUnop<T>(
3922 node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3923 MachineRepresentation::kNone);
3924 }
3925 case IrOpcode::kCompareMaps:
3926 return VisitUnop<T>(
3927 node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3928 MachineRepresentation::kBit);
3929 case IrOpcode::kEnsureWritableFastElements:
3930 return VisitBinop<T>(node, UseInfo::AnyTagged(),
3931 MachineRepresentation::kTaggedPointer);
3932 case IrOpcode::kMaybeGrowFastElements: {
3933 ProcessInput<T>(node, 0, UseInfo::AnyTagged()); // object
3934 ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // elements
3935 ProcessInput<T>(node, 2, UseInfo::TruncatingWord32()); // index
3936 ProcessInput<T>(node, 3, UseInfo::TruncatingWord32()); // length
3937 ProcessRemainingInputs<T>(node, 4);
3938 SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3939 return;
3940 }
3941
3942 case IrOpcode::kDateNow:
3943 VisitInputs<T>(node);
3944 return SetOutput<T>(node, MachineRepresentation::kTagged);
3945 case IrOpcode::kFrameState:
3946 return VisitFrameState<T>(FrameState{node});
3947 case IrOpcode::kStateValues:
3948 return VisitStateValues<T>(node);
3949 case IrOpcode::kObjectState:
3950 return VisitObjectState<T>(node);
3951 case IrOpcode::kObjectId:
3952 return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3953
3954 case IrOpcode::kTypeGuard: {
3955 if (truncation.IsUnused()) return VisitUnused<T>(node);
3956
3957 // We just get rid of the sigma here, choosing the best representation
3958 // for the sigma's type.
3959 Type type = TypeOf(node);
3960 MachineRepresentation representation =
3961 GetOutputInfoForPhi(node, type, truncation);
3962
3963 // Here we pretend that the input has the sigma's type for the
3964 // conversion.
3965 UseInfo use(representation, truncation);
3966 if (propagate<T>()) {
3967 EnqueueInput<T>(node, 0, use);
3968 } else if (lower<T>()) {
3969 ConvertInput(node, 0, use, type);
3970 }
3971 ProcessRemainingInputs<T>(node, 1);
3972 SetOutput<T>(node, representation);
3973 return;
3974 }
3975
3976 case IrOpcode::kFoldConstant:
3977 VisitInputs<T>(node);
3978 return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3979
3980 case IrOpcode::kFinishRegion:
3981 VisitInputs<T>(node);
3982 // Assume the output is tagged pointer.
3983 return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3984
3985 case IrOpcode::kReturn:
3986 VisitReturn<T>(node);
3987 // Assume the output is tagged.
3988 return SetOutput<T>(node, MachineRepresentation::kTagged);
3989
3990 case IrOpcode::kFindOrderedHashMapEntry: {
3991 Type const key_type = TypeOf(node->InputAt(1));
3992 if (key_type.Is(Type::Signed32OrMinusZero())) {
3993 VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
3994 MachineType::PointerRepresentation());
3995 if (lower<T>()) {
3996 ChangeOp(
3997 node,
3998 lowering->simplified()->FindOrderedHashMapEntryForInt32Key());
3999 }
4000 } else {
4001 VisitBinop<T>(node, UseInfo::AnyTagged(),
4002 MachineRepresentation::kTaggedSigned);
4003 }
4004 return;
4005 }
4006
4007 case IrOpcode::kFastApiCall: {
4008 VisitFastApiCall<T>(node, lowering);
4009 return;
4010 }
4011
4012 // Operators with all inputs tagged and no or tagged output have uniform
4013 // handling.
4014 case IrOpcode::kEnd:
4015 case IrOpcode::kIfSuccess:
4016 case IrOpcode::kIfException:
4017 case IrOpcode::kIfTrue:
4018 case IrOpcode::kIfFalse:
4019 case IrOpcode::kIfValue:
4020 case IrOpcode::kIfDefault:
4021 case IrOpcode::kDeoptimize:
4022 case IrOpcode::kEffectPhi:
4023 case IrOpcode::kTerminate:
4024 case IrOpcode::kCheckpoint:
4025 case IrOpcode::kLoop:
4026 case IrOpcode::kMerge:
4027 case IrOpcode::kThrow:
4028 case IrOpcode::kBeginRegion:
4029 case IrOpcode::kProjection:
4030 case IrOpcode::kOsrValue:
4031 case IrOpcode::kArgumentsElementsState:
4032 case IrOpcode::kArgumentsLengthState:
4033 case IrOpcode::kUnreachable:
4034 case IrOpcode::kRuntimeAbort:
4035 // All JavaScript operators except JSToNumber, JSToNumberConvertBigInt,
4036 // kJSToNumeric and JSWasmCall have uniform handling.
4037 #define OPCODE_CASE(name, ...) case IrOpcode::k##name:
4038 JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
4039 JS_OBJECT_OP_LIST(OPCODE_CASE)
4040 JS_CONTEXT_OP_LIST(OPCODE_CASE)
4041 JS_OTHER_OP_LIST(OPCODE_CASE)
4042 #undef OPCODE_CASE
4043 case IrOpcode::kJSBitwiseNot:
4044 case IrOpcode::kJSDecrement:
4045 case IrOpcode::kJSIncrement:
4046 case IrOpcode::kJSNegate:
4047 case IrOpcode::kJSToLength:
4048 case IrOpcode::kJSToName:
4049 case IrOpcode::kJSToObject:
4050 case IrOpcode::kJSToString:
4051 case IrOpcode::kJSParseInt:
4052 #if V8_ENABLE_WEBASSEMBLY
4053 if (node->opcode() == IrOpcode::kJSWasmCall) {
4054 return VisitJSWasmCall<T>(node, lowering);
4055 }
4056 #endif // V8_ENABLE_WEBASSEMBLY
4057 VisitInputs<T>(node);
4058 // Assume the output is tagged.
4059 return SetOutput<T>(node, MachineRepresentation::kTagged);
4060 case IrOpcode::kDeadValue:
4061 ProcessInput<T>(node, 0, UseInfo::Any());
4062 return SetOutput<T>(node, MachineRepresentation::kNone);
4063 case IrOpcode::kStaticAssert:
4064 DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
4065 return VisitUnop<T>(node, UseInfo::Bool(),
4066 MachineRepresentation::kTagged);
4067 case IrOpcode::kAssertType:
4068 return VisitUnop<T>(node, UseInfo::AnyTagged(),
4069 MachineRepresentation::kTagged);
4070 case IrOpcode::kVerifyType: {
4071 Type inputType = TypeOf(node->InputAt(0));
4072 VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged,
4073 inputType);
4074 if (lower<T>()) {
4075 if (inputType.CanBeAsserted()) {
4076 ChangeOp(node, simplified()->AssertType(inputType));
4077 } else {
4078 if (!FLAG_fuzzing) {
4079 #ifdef DEBUG
4080 inputType.Print();
4081 #endif
4082 FATAL("%%VerifyType: unsupported type");
4083 }
4084 DeferReplacement(node, node->InputAt(0));
4085 }
4086 }
4087 return;
4088 }
4089
4090 default:
4091 FATAL(
4092 "Representation inference: unsupported opcode %i (%s), node #%i\n.",
4093 node->opcode(), node->op()->mnemonic(), node->id());
4094 break;
4095 }
4096 UNREACHABLE();
4097 }
4098
DisconnectFromEffectAndControl(Node * node)4099 void DisconnectFromEffectAndControl(Node* node) {
4100 if (node->op()->EffectInputCount() == 1) {
4101 Node* control = NodeProperties::GetControlInput(node);
4102 Node* effect = NodeProperties::GetEffectInput(node);
4103 ReplaceEffectControlUses(node, effect, control);
4104 } else {
4105 DCHECK_EQ(0, node->op()->EffectInputCount());
4106 DCHECK_EQ(0, node->op()->ControlOutputCount());
4107 DCHECK_EQ(0, node->op()->EffectOutputCount());
4108 }
4109 }
4110
DeferReplacement(Node * node,Node * replacement)4111 void DeferReplacement(Node* node, Node* replacement) {
4112 TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
4113 node->op()->mnemonic(), replacement->id(),
4114 replacement->op()->mnemonic());
4115
4116 DisconnectFromEffectAndControl(node);
4117 node->NullAllInputs(); // Node is now dead.
4118
4119 replacements_.push_back(node);
4120 replacements_.push_back(replacement);
4121
4122 NotifyNodeReplaced(node, replacement);
4123 }
4124
InsertTypeOverrideForVerifier(const Type & type,Node * node)4125 Node* InsertTypeOverrideForVerifier(const Type& type, Node* node) {
4126 if (verification_enabled()) {
4127 DCHECK(!type.IsInvalid());
4128 node = graph()->NewNode(common()->SLVerifierHint(nullptr, type), node);
4129 verifier_->RecordHint(node);
4130 }
4131 return node;
4132 }
4133
ChangeToSemanticsHintForVerifier(Node * node,const Operator * semantics)4134 void ChangeToSemanticsHintForVerifier(Node* node, const Operator* semantics) {
4135 DCHECK_EQ(node->op()->ValueInputCount(), 1);
4136 DCHECK_EQ(node->op()->EffectInputCount(), 0);
4137 DCHECK_EQ(node->op()->ControlInputCount(), 0);
4138 if (verification_enabled()) {
4139 ChangeOp(node, common()->SLVerifierHint(semantics, base::nullopt));
4140 verifier_->RecordHint(node);
4141 } else {
4142 DeferReplacement(node, node->InputAt(0));
4143 }
4144 }
4145
4146 private:
ChangeOp(Node * node,const Operator * new_op)4147 void ChangeOp(Node* node, const Operator* new_op) {
4148 compiler::NodeProperties::ChangeOp(node, new_op);
4149
4150 if (V8_UNLIKELY(observe_node_manager_ != nullptr))
4151 observe_node_manager_->OnNodeChanged(kSimplifiedLoweringReducerName, node,
4152 node);
4153 }
4154
NotifyNodeReplaced(Node * node,Node * replacement)4155 void NotifyNodeReplaced(Node* node, Node* replacement) {
4156 if (V8_UNLIKELY(observe_node_manager_ != nullptr))
4157 observe_node_manager_->OnNodeChanged(kSimplifiedLoweringReducerName, node,
4158 replacement);
4159 }
4160
4161 JSGraph* jsgraph_;
4162 JSHeapBroker* broker_;
4163 Zone* zone_; // Temporary zone.
4164 // Map from node to its uses that might need to be revisited.
4165 ZoneMap<Node*, ZoneVector<Node*>> might_need_revisit_;
4166 size_t count_; // number of nodes in the graph
4167 ZoneVector<NodeInfo> info_; // node id -> usage information
4168 #ifdef DEBUG
4169 ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about
4170 // requirements on inputs.
4171 #endif // DEBUG
4172 NodeVector replacements_; // replacements to be done after lowering
4173 RepresentationChanger* changer_; // for inserting representation changes
4174 ZoneQueue<Node*> revisit_queue_; // Queue for revisiting nodes.
4175
4176 struct NodeState {
4177 Node* node;
4178 int input_index;
4179 };
4180 NodeVector traversal_nodes_; // Order in which to traverse the nodes.
4181 // TODO(danno): RepresentationSelector shouldn't know anything about the
4182 // source positions table, but must for now since there currently is no other
4183 // way to pass down source position information to nodes created during
4184 // lowering. Once this phase becomes a vanilla reducer, it should get source
4185 // position information via the SourcePositionWrapper like all other reducers.
4186 SourcePositionTable* source_positions_;
4187 NodeOriginTable* node_origins_;
4188 TypeCache const* type_cache_;
4189 OperationTyper op_typer_; // helper for the feedback typer
4190 TickCounter* const tick_counter_;
4191 Linkage* const linkage_;
4192 ObserveNodeManager* const observe_node_manager_;
4193 SimplifiedLoweringVerifier* verifier_; // Used to verify output graph.
4194
GetInfo(Node * node)4195 NodeInfo* GetInfo(Node* node) {
4196 DCHECK(node->id() < count_);
4197 return &info_[node->id()];
4198 }
zone()4199 Zone* zone() { return zone_; }
graph_zone()4200 Zone* graph_zone() { return jsgraph_->zone(); }
linkage()4201 Linkage* linkage() { return linkage_; }
4202 };
4203
4204 // Template specializations
4205
4206 // Enqueue {use_node}'s {index} input if the {use_info} contains new information
4207 // for that input node.
4208 template <>
EnqueueInput(Node * use_node,int index,UseInfo use_info)4209 void RepresentationSelector::EnqueueInput<PROPAGATE>(Node* use_node, int index,
4210 UseInfo use_info) {
4211 Node* node = use_node->InputAt(index);
4212 NodeInfo* info = GetInfo(node);
4213 #ifdef DEBUG
4214 // Check monotonicity of input requirements.
4215 node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
4216 use_info);
4217 #endif // DEBUG
4218 if (info->unvisited()) {
4219 info->AddUse(use_info);
4220 TRACE(" initial #%i: %s\n", node->id(), info->truncation().description());
4221 return;
4222 }
4223 TRACE(" queue #%i?: %s\n", node->id(), info->truncation().description());
4224 if (info->AddUse(use_info)) {
4225 // New usage information for the node is available.
4226 if (!info->queued()) {
4227 DCHECK(info->visited());
4228 revisit_queue_.push(node);
4229 info->set_queued();
4230 TRACE(" added: %s\n", info->truncation().description());
4231 } else {
4232 TRACE(" inqueue: %s\n", info->truncation().description());
4233 }
4234 }
4235 }
4236
4237 template <>
SetOutput(Node * node,MachineRepresentation representation,Type restriction_type)4238 void RepresentationSelector::SetOutput<PROPAGATE>(
4239 Node* node, MachineRepresentation representation, Type restriction_type) {
4240 NodeInfo* const info = GetInfo(node);
4241 info->set_restriction_type(restriction_type);
4242 }
4243
4244 template <>
SetOutput(Node * node,MachineRepresentation representation,Type restriction_type)4245 void RepresentationSelector::SetOutput<RETYPE>(
4246 Node* node, MachineRepresentation representation, Type restriction_type) {
4247 NodeInfo* const info = GetInfo(node);
4248 DCHECK(restriction_type.Is(info->restriction_type()));
4249 info->set_output(representation);
4250 }
4251
4252 template <>
SetOutput(Node * node,MachineRepresentation representation,Type restriction_type)4253 void RepresentationSelector::SetOutput<LOWER>(
4254 Node* node, MachineRepresentation representation, Type restriction_type) {
4255 NodeInfo* const info = GetInfo(node);
4256 DCHECK_EQ(info->representation(), representation);
4257 DCHECK(restriction_type.Is(info->restriction_type()));
4258 USE(info);
4259 }
4260
4261 template <>
ProcessInput(Node * node,int index,UseInfo use)4262 void RepresentationSelector::ProcessInput<PROPAGATE>(Node* node, int index,
4263 UseInfo use) {
4264 DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
4265 !node->op()->HasProperty(Operator::kNoDeopt) &&
4266 node->op()->EffectInputCount() > 0);
4267 EnqueueInput<PROPAGATE>(node, index, use);
4268 }
4269
4270 template <>
ProcessInput(Node * node,int index,UseInfo use)4271 void RepresentationSelector::ProcessInput<RETYPE>(Node* node, int index,
4272 UseInfo use) {
4273 DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
4274 !node->op()->HasProperty(Operator::kNoDeopt) &&
4275 node->op()->EffectInputCount() > 0);
4276 }
4277
4278 template <>
ProcessInput(Node * node,int index,UseInfo use)4279 void RepresentationSelector::ProcessInput<LOWER>(Node* node, int index,
4280 UseInfo use) {
4281 DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
4282 !node->op()->HasProperty(Operator::kNoDeopt) &&
4283 node->op()->EffectInputCount() > 0);
4284 ConvertInput(node, index, use);
4285 }
4286
4287 template <>
ProcessRemainingInputs(Node * node,int index)4288 void RepresentationSelector::ProcessRemainingInputs<PROPAGATE>(Node* node,
4289 int index) {
4290 DCHECK_GE(index, NodeProperties::PastContextIndex(node));
4291
4292 // Enqueue other inputs (effects, control).
4293 for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
4294 i < node->InputCount(); ++i) {
4295 EnqueueInput<PROPAGATE>(node, i);
4296 }
4297 }
4298
4299 // The default, most general visitation case. For {node}, process all value,
4300 // context, frame state, effect, and control inputs, assuming that value
4301 // inputs should have {kRepTagged} representation and can observe all output
4302 // values {kTypeAny}.
4303 template <>
VisitInputs(Node * node)4304 void RepresentationSelector::VisitInputs<PROPAGATE>(Node* node) {
4305 int first_effect_index = NodeProperties::FirstEffectIndex(node);
4306 // Visit value, context and frame state inputs as tagged.
4307 for (int i = 0; i < first_effect_index; i++) {
4308 ProcessInput<PROPAGATE>(node, i, UseInfo::AnyTagged());
4309 }
4310 // Only enqueue other inputs (effects, control).
4311 for (int i = first_effect_index; i < node->InputCount(); i++) {
4312 EnqueueInput<PROPAGATE>(node, i);
4313 }
4314 }
4315
4316 template <>
VisitInputs(Node * node)4317 void RepresentationSelector::VisitInputs<LOWER>(Node* node) {
4318 int first_effect_index = NodeProperties::FirstEffectIndex(node);
4319 // Visit value, context and frame state inputs as tagged.
4320 for (int i = 0; i < first_effect_index; i++) {
4321 ProcessInput<LOWER>(node, i, UseInfo::AnyTagged());
4322 }
4323 }
4324
4325 template <>
InsertUnreachableIfNecessary(Node * node)4326 void RepresentationSelector::InsertUnreachableIfNecessary<LOWER>(Node* node) {
4327 // If the node is effectful and it produces an impossible value, then we
4328 // insert Unreachable node after it.
4329 if (node->op()->ValueOutputCount() > 0 &&
4330 node->op()->EffectOutputCount() > 0 &&
4331 node->opcode() != IrOpcode::kUnreachable && TypeOf(node).IsNone()) {
4332 Node* control = (node->op()->ControlOutputCount() == 0)
4333 ? NodeProperties::GetControlInput(node, 0)
4334 : NodeProperties::FindSuccessfulControlProjection(node);
4335
4336 Node* unreachable =
4337 graph()->NewNode(common()->Unreachable(), node, control);
4338
4339 // Insert unreachable node and replace all the effect uses of the {node}
4340 // with the new unreachable node.
4341 for (Edge edge : node->use_edges()) {
4342 if (!NodeProperties::IsEffectEdge(edge)) continue;
4343 // Make sure to not overwrite the unreachable node's input. That would
4344 // create a cycle.
4345 if (edge.from() == unreachable) continue;
4346 // Avoid messing up the exceptional path.
4347 if (edge.from()->opcode() == IrOpcode::kIfException) {
4348 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
4349 DCHECK_EQ(NodeProperties::GetControlInput(edge.from()), node);
4350 continue;
4351 }
4352
4353 edge.UpdateTo(unreachable);
4354 }
4355 }
4356 }
4357
SimplifiedLowering(JSGraph * jsgraph,JSHeapBroker * broker,Zone * zone,SourcePositionTable * source_positions,NodeOriginTable * node_origins,TickCounter * tick_counter,Linkage * linkage,OptimizedCompilationInfo * info,ObserveNodeManager * observe_node_manager)4358 SimplifiedLowering::SimplifiedLowering(
4359 JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
4360 SourcePositionTable* source_positions, NodeOriginTable* node_origins,
4361 TickCounter* tick_counter, Linkage* linkage, OptimizedCompilationInfo* info,
4362 ObserveNodeManager* observe_node_manager)
4363 : jsgraph_(jsgraph),
4364 broker_(broker),
4365 zone_(zone),
4366 type_cache_(TypeCache::Get()),
4367 source_positions_(source_positions),
4368 node_origins_(node_origins),
4369 tick_counter_(tick_counter),
4370 linkage_(linkage),
4371 info_(info),
4372 observe_node_manager_(observe_node_manager) {}
4373
LowerAllNodes()4374 void SimplifiedLowering::LowerAllNodes() {
4375 SimplifiedLoweringVerifier* verifier = nullptr;
4376 if (FLAG_verify_simplified_lowering) {
4377 verifier = zone_->New<SimplifiedLoweringVerifier>(zone_, graph());
4378 }
4379 RepresentationChanger changer(jsgraph(), broker_, verifier);
4380 RepresentationSelector selector(
4381 jsgraph(), broker_, zone_, &changer, source_positions_, node_origins_,
4382 tick_counter_, linkage_, observe_node_manager_, verifier);
4383 selector.Run(this);
4384 }
4385
DoJSToNumberOrNumericTruncatesToFloat64(Node * node,RepresentationSelector * selector)4386 void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
4387 Node* node, RepresentationSelector* selector) {
4388 DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
4389 node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
4390 node->opcode() == IrOpcode::kJSToNumeric);
4391 Node* value = node->InputAt(0);
4392 Node* context = node->InputAt(1);
4393 Node* frame_state = node->InputAt(2);
4394 Node* effect = node->InputAt(3);
4395 Node* control = node->InputAt(4);
4396
4397 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
4398 Node* branch0 =
4399 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
4400
4401 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4402 Node* etrue0 = effect;
4403 Node* vtrue0;
4404 {
4405 vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
4406 vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
4407 }
4408
4409 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4410 Node* efalse0 = effect;
4411 Node* vfalse0;
4412 {
4413 Operator const* op =
4414 node->opcode() == IrOpcode::kJSToNumber
4415 ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4416 ? ToNumberConvertBigIntOperator()
4417 : ToNumberOperator())
4418 : ToNumericOperator();
4419 Node* code = node->opcode() == IrOpcode::kJSToNumber
4420 ? ToNumberCode()
4421 : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4422 ? ToNumberConvertBigIntCode()
4423 : ToNumericCode());
4424 vfalse0 = efalse0 = if_false0 = graph()->NewNode(
4425 op, code, value, context, frame_state, efalse0, if_false0);
4426
4427 // Update potential {IfException} uses of {node} to point to the above
4428 // stub call node instead.
4429 Node* on_exception = nullptr;
4430 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
4431 NodeProperties::ReplaceControlInput(on_exception, vfalse0);
4432 NodeProperties::ReplaceEffectInput(on_exception, efalse0);
4433 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
4434 }
4435
4436 Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
4437 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4438
4439 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4440 Node* etrue1 = efalse0;
4441 Node* vtrue1;
4442 {
4443 vtrue1 =
4444 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
4445 vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
4446 }
4447
4448 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4449 Node* efalse1 = efalse0;
4450 Node* vfalse1;
4451 {
4452 vfalse1 = efalse1 = graph()->NewNode(
4453 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
4454 efalse1, if_false1);
4455 }
4456
4457 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
4458 efalse0 =
4459 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
4460 vfalse0 =
4461 graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
4462 vtrue1, vfalse1, if_false0);
4463 }
4464
4465 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
4466 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
4467 value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
4468 vtrue0, vfalse0, control);
4469
4470 // Replace effect and control uses appropriately.
4471 for (Edge edge : node->use_edges()) {
4472 if (NodeProperties::IsControlEdge(edge)) {
4473 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
4474 edge.from()->ReplaceUses(control);
4475 edge.from()->Kill();
4476 } else {
4477 DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
4478 edge.UpdateTo(control);
4479 }
4480 } else if (NodeProperties::IsEffectEdge(edge)) {
4481 edge.UpdateTo(effect);
4482 }
4483 }
4484
4485 selector->DeferReplacement(node, value);
4486 }
4487
DoJSToNumberOrNumericTruncatesToWord32(Node * node,RepresentationSelector * selector)4488 void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
4489 Node* node, RepresentationSelector* selector) {
4490 DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
4491 node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
4492 node->opcode() == IrOpcode::kJSToNumeric);
4493 Node* value = node->InputAt(0);
4494 Node* context = node->InputAt(1);
4495 Node* frame_state = node->InputAt(2);
4496 Node* effect = node->InputAt(3);
4497 Node* control = node->InputAt(4);
4498
4499 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
4500 Node* branch0 =
4501 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
4502
4503 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4504 Node* etrue0 = effect;
4505 Node* vtrue0 =
4506 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
4507
4508 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4509 Node* efalse0 = effect;
4510 Node* vfalse0;
4511 {
4512 Operator const* op =
4513 node->opcode() == IrOpcode::kJSToNumber
4514 ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4515 ? ToNumberConvertBigIntOperator()
4516 : ToNumberOperator())
4517 : ToNumericOperator();
4518 Node* code = node->opcode() == IrOpcode::kJSToNumber
4519 ? ToNumberCode()
4520 : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
4521 ? ToNumberConvertBigIntCode()
4522 : ToNumericCode());
4523 vfalse0 = efalse0 = if_false0 = graph()->NewNode(
4524 op, code, value, context, frame_state, efalse0, if_false0);
4525
4526 // Update potential {IfException} uses of {node} to point to the above
4527 // stub call node instead.
4528 Node* on_exception = nullptr;
4529 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
4530 NodeProperties::ReplaceControlInput(on_exception, vfalse0);
4531 NodeProperties::ReplaceEffectInput(on_exception, efalse0);
4532 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
4533 }
4534
4535 Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
4536 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4537
4538 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4539 Node* etrue1 = efalse0;
4540 Node* vtrue1 =
4541 graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
4542
4543 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4544 Node* efalse1 = efalse0;
4545 Node* vfalse1;
4546 {
4547 vfalse1 = efalse1 = graph()->NewNode(
4548 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
4549 efalse1, if_false1);
4550 vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
4551 }
4552
4553 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
4554 efalse0 =
4555 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
4556 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
4557 vtrue1, vfalse1, if_false0);
4558 }
4559
4560 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
4561 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
4562 value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
4563 vtrue0, vfalse0, control);
4564
4565 // Replace effect and control uses appropriately.
4566 for (Edge edge : node->use_edges()) {
4567 if (NodeProperties::IsControlEdge(edge)) {
4568 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
4569 edge.from()->ReplaceUses(control);
4570 edge.from()->Kill();
4571 } else {
4572 DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
4573 edge.UpdateTo(control);
4574 }
4575 } else if (NodeProperties::IsEffectEdge(edge)) {
4576 edge.UpdateTo(effect);
4577 }
4578 }
4579
4580 selector->DeferReplacement(node, value);
4581 }
4582
Float64Round(Node * const node)4583 Node* SimplifiedLowering::Float64Round(Node* const node) {
4584 Node* const one = jsgraph()->Float64Constant(1.0);
4585 Node* const one_half = jsgraph()->Float64Constant(0.5);
4586 Node* const input = node->InputAt(0);
4587
4588 // Round up towards Infinity, and adjust if the difference exceeds 0.5.
4589 Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
4590 node->InputAt(0));
4591 return graph()->NewNode(
4592 common()->Select(MachineRepresentation::kFloat64),
4593 graph()->NewNode(
4594 machine()->Float64LessThanOrEqual(),
4595 graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
4596 result, graph()->NewNode(machine()->Float64Sub(), result, one));
4597 }
4598
Float64Sign(Node * const node)4599 Node* SimplifiedLowering::Float64Sign(Node* const node) {
4600 Node* const minus_one = jsgraph()->Float64Constant(-1.0);
4601 Node* const zero = jsgraph()->Float64Constant(0.0);
4602 Node* const one = jsgraph()->Float64Constant(1.0);
4603
4604 Node* const input = node->InputAt(0);
4605
4606 return graph()->NewNode(
4607 common()->Select(MachineRepresentation::kFloat64),
4608 graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
4609 graph()->NewNode(
4610 common()->Select(MachineRepresentation::kFloat64),
4611 graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
4612 input));
4613 }
4614
Int32Abs(Node * const node)4615 Node* SimplifiedLowering::Int32Abs(Node* const node) {
4616 Node* const input = node->InputAt(0);
4617
4618 // Generate case for absolute integer value.
4619 //
4620 // let sign = input >> 31 in
4621 // (input ^ sign) - sign
4622
4623 Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
4624 jsgraph()->Int32Constant(31));
4625 return graph()->NewNode(machine()->Int32Sub(),
4626 graph()->NewNode(machine()->Word32Xor(), input, sign),
4627 sign);
4628 }
4629
Int32Div(Node * const node)4630 Node* SimplifiedLowering::Int32Div(Node* const node) {
4631 Int32BinopMatcher m(node);
4632 Node* const zero = jsgraph()->Int32Constant(0);
4633 Node* const minus_one = jsgraph()->Int32Constant(-1);
4634 Node* const lhs = m.left().node();
4635 Node* const rhs = m.right().node();
4636
4637 if (m.right().Is(-1)) {
4638 return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
4639 } else if (m.right().Is(0)) {
4640 return rhs;
4641 } else if (machine()->Int32DivIsSafe() || m.right().HasResolvedValue()) {
4642 return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
4643 }
4644
4645 // General case for signed integer division.
4646 //
4647 // if 0 < rhs then
4648 // lhs / rhs
4649 // else
4650 // if rhs < -1 then
4651 // lhs / rhs
4652 // else if rhs == 0 then
4653 // 0
4654 // else
4655 // 0 - lhs
4656 //
4657 // Note: We do not use the Diamond helper class here, because it really hurts
4658 // readability with nested diamonds.
4659 const Operator* const merge_op = common()->Merge(2);
4660 const Operator* const phi_op =
4661 common()->Phi(MachineRepresentation::kWord32, 2);
4662
4663 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
4664 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
4665 graph()->start());
4666
4667 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4668 Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
4669
4670 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4671 Node* false0;
4672 {
4673 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
4674 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4675
4676 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4677 Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);
4678
4679 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4680 Node* false1;
4681 {
4682 Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4683 Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);
4684
4685 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
4686 Node* true2 = zero;
4687
4688 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
4689 Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
4690
4691 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
4692 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
4693 }
4694
4695 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4696 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4697 }
4698
4699 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4700 return graph()->NewNode(phi_op, true0, false0, merge0);
4701 }
4702
Int32Mod(Node * const node)4703 Node* SimplifiedLowering::Int32Mod(Node* const node) {
4704 Int32BinopMatcher m(node);
4705 Node* const zero = jsgraph()->Int32Constant(0);
4706 Node* const minus_one = jsgraph()->Int32Constant(-1);
4707 Node* const lhs = m.left().node();
4708 Node* const rhs = m.right().node();
4709
4710 if (m.right().Is(-1) || m.right().Is(0)) {
4711 return zero;
4712 } else if (m.right().HasResolvedValue()) {
4713 return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
4714 }
4715
4716 // General case for signed integer modulus, with optimization for (unknown)
4717 // power of 2 right hand side.
4718 //
4719 // if 0 < rhs then
4720 // msk = rhs - 1
4721 // if rhs & msk != 0 then
4722 // lhs % rhs
4723 // else
4724 // if lhs < 0 then
4725 // -(-lhs & msk)
4726 // else
4727 // lhs & msk
4728 // else
4729 // if rhs < -1 then
4730 // lhs % rhs
4731 // else
4732 // zero
4733 //
4734 // Note: We do not use the Diamond helper class here, because it really hurts
4735 // readability with nested diamonds.
4736 const Operator* const merge_op = common()->Merge(2);
4737 const Operator* const phi_op =
4738 common()->Phi(MachineRepresentation::kWord32, 2);
4739
4740 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
4741 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
4742 graph()->start());
4743
4744 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4745 Node* true0;
4746 {
4747 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
4748
4749 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
4750 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);
4751
4752 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4753 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
4754
4755 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4756 Node* false1;
4757 {
4758 Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
4759 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
4760 check2, if_false1);
4761
4762 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
4763 Node* true2 = graph()->NewNode(
4764 machine()->Int32Sub(), zero,
4765 graph()->NewNode(machine()->Word32And(),
4766 graph()->NewNode(machine()->Int32Sub(), zero, lhs),
4767 msk));
4768
4769 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
4770 Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);
4771
4772 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
4773 false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
4774 }
4775
4776 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
4777 true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
4778 }
4779
4780 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4781 Node* false0;
4782 {
4783 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
4784 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
4785 check1, if_false0);
4786
4787 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4788 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);
4789
4790 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4791 Node* false1 = zero;
4792
4793 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4794 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4795 }
4796
4797 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4798 return graph()->NewNode(phi_op, true0, false0, merge0);
4799 }
4800
Int32Sign(Node * const node)4801 Node* SimplifiedLowering::Int32Sign(Node* const node) {
4802 Node* const minus_one = jsgraph()->Int32Constant(-1);
4803 Node* const zero = jsgraph()->Int32Constant(0);
4804 Node* const one = jsgraph()->Int32Constant(1);
4805
4806 Node* const input = node->InputAt(0);
4807
4808 return graph()->NewNode(
4809 common()->Select(MachineRepresentation::kWord32),
4810 graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
4811 graph()->NewNode(
4812 common()->Select(MachineRepresentation::kWord32),
4813 graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
4814 zero));
4815 }
4816
Uint32Div(Node * const node)4817 Node* SimplifiedLowering::Uint32Div(Node* const node) {
4818 Uint32BinopMatcher m(node);
4819 Node* const zero = jsgraph()->Uint32Constant(0);
4820 Node* const lhs = m.left().node();
4821 Node* const rhs = m.right().node();
4822
4823 if (m.right().Is(0)) {
4824 return zero;
4825 } else if (machine()->Uint32DivIsSafe() || m.right().HasResolvedValue()) {
4826 return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
4827 }
4828
4829 Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4830 Diamond d(graph(), common(), check, BranchHint::kFalse);
4831 Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
4832 return d.Phi(MachineRepresentation::kWord32, zero, div);
4833 }
4834
Uint32Mod(Node * const node)4835 Node* SimplifiedLowering::Uint32Mod(Node* const node) {
4836 Uint32BinopMatcher m(node);
4837 Node* const minus_one = jsgraph()->Int32Constant(-1);
4838 Node* const zero = jsgraph()->Uint32Constant(0);
4839 Node* const lhs = m.left().node();
4840 Node* const rhs = m.right().node();
4841
4842 if (m.right().Is(0)) {
4843 return zero;
4844 } else if (m.right().HasResolvedValue()) {
4845 return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
4846 }
4847
4848 // General case for unsigned integer modulus, with optimization for (unknown)
4849 // power of 2 right hand side.
4850 //
4851 // if rhs == 0 then
4852 // zero
4853 // else
4854 // msk = rhs - 1
4855 // if rhs & msk != 0 then
4856 // lhs % rhs
4857 // else
4858 // lhs & msk
4859 //
4860 // Note: We do not use the Diamond helper class here, because it really hurts
4861 // readability with nested diamonds.
4862 const Operator* const merge_op = common()->Merge(2);
4863 const Operator* const phi_op =
4864 common()->Phi(MachineRepresentation::kWord32, 2);
4865
4866 Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4867 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
4868 graph()->start());
4869
4870 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4871 Node* true0 = zero;
4872
4873 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
4874 Node* false0;
4875 {
4876 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);
4877
4878 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
4879 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4880
4881 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
4882 Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);
4883
4884 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
4885 Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);
4886
4887 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
4888 false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4889 }
4890
4891 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
4892 return graph()->NewNode(phi_op, true0, false0, merge0);
4893 }
4894
DoMax(Node * node,Operator const * op,MachineRepresentation rep)4895 void SimplifiedLowering::DoMax(Node* node, Operator const* op,
4896 MachineRepresentation rep) {
4897 Node* const lhs = node->InputAt(0);
4898 Node* const rhs = node->InputAt(1);
4899
4900 node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
4901 DCHECK_EQ(rhs, node->InputAt(1));
4902 node->AppendInput(graph()->zone(), lhs);
4903 ChangeOp(node, common()->Select(rep));
4904 }
4905
DoMin(Node * node,Operator const * op,MachineRepresentation rep)4906 void SimplifiedLowering::DoMin(Node* node, Operator const* op,
4907 MachineRepresentation rep) {
4908 Node* const lhs = node->InputAt(0);
4909 Node* const rhs = node->InputAt(1);
4910
4911 node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
4912 DCHECK_EQ(lhs, node->InputAt(1));
4913 DCHECK_EQ(rhs, node->InputAt(2));
4914 ChangeOp(node, common()->Select(rep));
4915 }
4916
DoIntegral32ToBit(Node * node)4917 void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
4918 Node* const input = node->InputAt(0);
4919 Node* const zero = jsgraph()->Int32Constant(0);
4920 Operator const* const op = machine()->Word32Equal();
4921
4922 node->ReplaceInput(0, graph()->NewNode(op, input, zero));
4923 node->AppendInput(graph()->zone(), zero);
4924 ChangeOp(node, op);
4925 }
4926
DoOrderedNumberToBit(Node * node)4927 void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
4928 Node* const input = node->InputAt(0);
4929
4930 node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
4931 jsgraph()->Float64Constant(0.0)));
4932 node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
4933 ChangeOp(node, machine()->Word32Equal());
4934 }
4935
DoNumberToBit(Node * node)4936 void SimplifiedLowering::DoNumberToBit(Node* node) {
4937 Node* const input = node->InputAt(0);
4938
4939 node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
4940 node->AppendInput(graph()->zone(),
4941 graph()->NewNode(machine()->Float64Abs(), input));
4942 ChangeOp(node, machine()->Float64LessThan());
4943 }
4944
DoIntegerToUint8Clamped(Node * node)4945 void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
4946 Node* const input = node->InputAt(0);
4947 Node* const min = jsgraph()->Float64Constant(0.0);
4948 Node* const max = jsgraph()->Float64Constant(255.0);
4949
4950 node->ReplaceInput(
4951 0, graph()->NewNode(machine()->Float64LessThan(), min, input));
4952 node->AppendInput(
4953 graph()->zone(),
4954 graph()->NewNode(
4955 common()->Select(MachineRepresentation::kFloat64),
4956 graph()->NewNode(machine()->Float64LessThan(), input, max), input,
4957 max));
4958 node->AppendInput(graph()->zone(), min);
4959 ChangeOp(node, common()->Select(MachineRepresentation::kFloat64));
4960 }
4961
DoNumberToUint8Clamped(Node * node)4962 void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
4963 Node* const input = node->InputAt(0);
4964 Node* const min = jsgraph()->Float64Constant(0.0);
4965 Node* const max = jsgraph()->Float64Constant(255.0);
4966
4967 node->ReplaceInput(
4968 0, graph()->NewNode(
4969 common()->Select(MachineRepresentation::kFloat64),
4970 graph()->NewNode(machine()->Float64LessThan(), min, input),
4971 graph()->NewNode(
4972 common()->Select(MachineRepresentation::kFloat64),
4973 graph()->NewNode(machine()->Float64LessThan(), input, max),
4974 input, max),
4975 min));
4976 ChangeOp(node, machine()->Float64RoundTiesEven().placeholder());
4977 }
4978
DoSigned32ToUint8Clamped(Node * node)4979 void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
4980 Node* const input = node->InputAt(0);
4981 Node* const min = jsgraph()->Int32Constant(0);
4982 Node* const max = jsgraph()->Int32Constant(255);
4983
4984 node->ReplaceInput(
4985 0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
4986 node->AppendInput(
4987 graph()->zone(),
4988 graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
4989 graph()->NewNode(machine()->Int32LessThan(), input, min),
4990 min, input));
4991 node->AppendInput(graph()->zone(), max);
4992 ChangeOp(node, common()->Select(MachineRepresentation::kWord32));
4993 }
4994
DoUnsigned32ToUint8Clamped(Node * node)4995 void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
4996 Node* const input = node->InputAt(0);
4997 Node* const max = jsgraph()->Uint32Constant(255u);
4998
4999 node->ReplaceInput(
5000 0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
5001 node->AppendInput(graph()->zone(), input);
5002 node->AppendInput(graph()->zone(), max);
5003 ChangeOp(node, common()->Select(MachineRepresentation::kWord32));
5004 }
5005
ToNumberCode()5006 Node* SimplifiedLowering::ToNumberCode() {
5007 if (!to_number_code_.is_set()) {
5008 Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumber);
5009 to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
5010 }
5011 return to_number_code_.get();
5012 }
5013
ToNumberConvertBigIntCode()5014 Node* SimplifiedLowering::ToNumberConvertBigIntCode() {
5015 if (!to_number_convert_big_int_code_.is_set()) {
5016 Callable callable =
5017 Builtins::CallableFor(isolate(), Builtin::kToNumberConvertBigInt);
5018 to_number_convert_big_int_code_.set(
5019 jsgraph()->HeapConstant(callable.code()));
5020 }
5021 return to_number_convert_big_int_code_.get();
5022 }
5023
ToNumericCode()5024 Node* SimplifiedLowering::ToNumericCode() {
5025 if (!to_numeric_code_.is_set()) {
5026 Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumeric);
5027 to_numeric_code_.set(jsgraph()->HeapConstant(callable.code()));
5028 }
5029 return to_numeric_code_.get();
5030 }
5031
ToNumberOperator()5032 Operator const* SimplifiedLowering::ToNumberOperator() {
5033 if (!to_number_operator_.is_set()) {
5034 Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumber);
5035 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
5036 auto call_descriptor = Linkage::GetStubCallDescriptor(
5037 graph()->zone(), callable.descriptor(),
5038 callable.descriptor().GetStackParameterCount(), flags,
5039 Operator::kNoProperties);
5040 to_number_operator_.set(common()->Call(call_descriptor));
5041 }
5042 return to_number_operator_.get();
5043 }
5044
ToNumberConvertBigIntOperator()5045 Operator const* SimplifiedLowering::ToNumberConvertBigIntOperator() {
5046 if (!to_number_convert_big_int_operator_.is_set()) {
5047 Callable callable =
5048 Builtins::CallableFor(isolate(), Builtin::kToNumberConvertBigInt);
5049 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
5050 auto call_descriptor = Linkage::GetStubCallDescriptor(
5051 graph()->zone(), callable.descriptor(),
5052 callable.descriptor().GetStackParameterCount(), flags,
5053 Operator::kNoProperties);
5054 to_number_convert_big_int_operator_.set(common()->Call(call_descriptor));
5055 }
5056 return to_number_convert_big_int_operator_.get();
5057 }
5058
ToNumericOperator()5059 Operator const* SimplifiedLowering::ToNumericOperator() {
5060 if (!to_numeric_operator_.is_set()) {
5061 Callable callable = Builtins::CallableFor(isolate(), Builtin::kToNumeric);
5062 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
5063 auto call_descriptor = Linkage::GetStubCallDescriptor(
5064 graph()->zone(), callable.descriptor(),
5065 callable.descriptor().GetStackParameterCount(), flags,
5066 Operator::kNoProperties);
5067 to_numeric_operator_.set(common()->Call(call_descriptor));
5068 }
5069 return to_numeric_operator_.get();
5070 }
5071
ChangeOp(Node * node,const Operator * new_op)5072 void SimplifiedLowering::ChangeOp(Node* node, const Operator* new_op) {
5073 compiler::NodeProperties::ChangeOp(node, new_op);
5074
5075 if (V8_UNLIKELY(observe_node_manager_ != nullptr))
5076 observe_node_manager_->OnNodeChanged(kSimplifiedLoweringReducerName, node,
5077 node);
5078 }
5079
5080 #undef TRACE
5081
5082 } // namespace compiler
5083 } // namespace internal
5084 } // namespace v8
5085