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 39namespace v8 { 40namespace internal { 41namespace 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 49const 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. 57enum 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 80namespace { 81 82MachineRepresentation 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 106UseInfo 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 126UseInfo 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 144UseInfo 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 174UseInfo UseInfoForBasePointer(const FieldAccess& access) { 175 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word(); 176} 177 178UseInfo UseInfoForBasePointer(const ElementAccess& access) { 179 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word(); 180} 181 182void 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 195bool 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 223bool IsSomePositiveOrderedNumber(Type type) { 224 return type.Is(Type::OrderedNumber()) && (type.IsNone() || type.Min() > 0); 225} 226 227class JSONGraphWriterWithVerifierTypes : public JSONGraphWriter { 228 public: 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: 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. 248class InputUseInfos { 249 public: 250 explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {} 251 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 265 static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) { 266 return use1.truncation().IsLessGeneralThan(use2.truncation()); 267 } 268}; 269 270#endif // DEBUG 271 272class 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 { 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. 289 bool AddUse(UseInfo info) { 290 Truncation old_truncation = truncation_; 291 truncation_ = Truncation::Generalize(truncation_, info.truncation()); 292 return truncation_ != old_truncation; 293 } 294 295 void set_queued() { state_ = kQueued; } 296 void set_visited() { state_ = kVisited; } 297 void set_pushed() { state_ = kPushed; } 298 void reset_state() { state_ = kUnvisited; } 299 bool visited() const { return state_ == kVisited; } 300 bool queued() const { return state_ == kQueued; } 301 bool pushed() const { return state_ == kPushed; } 302 bool unvisited() const { return state_ == kUnvisited; } 303 Truncation truncation() const { return truncation_; } 304 void set_output(MachineRepresentation output) { representation_ = output; } 305 306 MachineRepresentation representation() const { return representation_; } 307 308 // Helpers for feedback typing. 309 void set_feedback_type(Type type) { feedback_type_ = type; } 310 Type feedback_type() const { return feedback_type_; } 311 void set_weakened() { weakened_ = true; } 312 bool weakened() const { return weakened_; } 313 void set_restriction_type(Type type) { restriction_type_ = type; } 314 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 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 360 bool verification_enabled() const { return verifier_ != nullptr; } 361 362 void ResetNodeInfoState() { 363 // Clean up for the next phase. 364 for (NodeInfo& info : info_) { 365 info.reset_state(); 366 } 367 } 368 369 Type TypeOf(Node* node) { 370 Type type = GetInfo(node)->feedback_type(); 371 return type.IsInvalid() ? NodeProperties::GetType(node) : type; 372 } 373 374 Type FeedbackTypeOf(Node* node) { 375 Type type = GetInfo(node)->feedback_type(); 376 return type.IsInvalid() ? Type::None() : type; 377 } 378 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 388 Type TypeSelect(Node* node) { 389 return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)), 390 FeedbackTypeOf(node->InputAt(2))); 391 } 392 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 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 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. 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 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. 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. 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. 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. 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. 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 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 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> 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> 804 static constexpr bool propagate() { 805 return T == PROPAGATE; 806 } 807 808 template <Phase T> 809 static constexpr bool retype() { 810 return T == RETYPE; 811 } 812 813 template <Phase T> 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 822 Type GetUpperBound(Node* node) { return NodeProperties::GetType(node); } 823 824 bool InputCannotBe(Node* node, Type type) { 825 DCHECK_EQ(1, node->op()->ValueInputCount()); 826 return !GetUpperBound(node->InputAt(0)).Maybe(type); 827 } 828 829 bool InputIs(Node* node, Type type) { 830 DCHECK_EQ(1, node->op()->ValueInputCount()); 831 return GetUpperBound(node->InputAt(0)).Is(type); 832 } 833 834 bool BothInputsAreSigned32(Node* node) { 835 return BothInputsAre(node, Type::Signed32()); 836 } 837 838 bool BothInputsAreUnsigned32(Node* node) { 839 return BothInputsAre(node, Type::Unsigned32()); 840 } 841 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 848 bool IsNodeRepresentationTagged(Node* node) { 849 MachineRepresentation representation = GetInfo(node)->representation(); 850 return IsAnyTagged(representation); 851 } 852 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 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. 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 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 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))}. 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> 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. 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 1106 void VisitFloat64Binop(Node* node) { 1107 VisitBinop<T>(node, UseInfo::TruncatingFloat64(), 1108 MachineRepresentation::kFloat64); 1109 } 1110 1111 template <Phase T> 1112 void VisitInt64Binop(Node* node) { 1113 VisitBinop<T>(node, UseInfo::Word64(), MachineRepresentation::kWord64); 1114 } 1115 1116 template <Phase T> 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. 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> 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> 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> 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> 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> 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 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 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 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> 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> 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> 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 1444 const Operator* Int32Op(Node* node) { 1445 return changer_->Int32OperatorFor(node->opcode()); 1446 } 1447 1448 const Operator* Int32OverflowOp(Node* node) { 1449 return changer_->Int32OverflowOperatorFor(node->opcode()); 1450 } 1451 1452 const Operator* Int64Op(Node* node) { 1453 return changer_->Int64OperatorFor(node->opcode()); 1454 } 1455 1456 const Operator* Uint32Op(Node* node) { 1457 return changer_->Uint32OperatorFor(node->opcode()); 1458 } 1459 1460 const Operator* Uint32OverflowOp(Node* node) { 1461 return changer_->Uint32OverflowOperatorFor(node->opcode()); 1462 } 1463 1464 const Operator* Float64Op(Node* node) { 1465 return changer_->Float64OperatorFor(node->opcode()); 1466 } 1467 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 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 1532 Graph* graph() const { return jsgraph_->graph(); } 1533 CommonOperatorBuilder* common() const { return jsgraph_->common(); } 1534 SimplifiedOperatorBuilder* simplified() const { 1535 return jsgraph_->simplified(); 1536 } 1537 1538 template <Phase T> 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 1565 void ChangeToInt32OverflowOp(Node* node) { 1566 ChangeOp(node, Int32OverflowOp(node)); 1567 } 1568 1569 void ChangeToUint32OverflowOp(Node* node) { 1570 ChangeOp(node, Uint32OverflowOp(node)); 1571 } 1572 1573 template <Phase T> 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> 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> 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> 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> 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 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> 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 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 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> 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> 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 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 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 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 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: 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 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 4195 NodeInfo* GetInfo(Node* node) { 4196 DCHECK(node->id() < count_); 4197 return &info_[node->id()]; 4198 } 4199 Zone* zone() { return zone_; } 4200 Zone* graph_zone() { return jsgraph_->zone(); } 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. 4208template <> 4209void 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 4237template <> 4238void 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 4244template <> 4245void 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 4252template <> 4253void 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 4261template <> 4262void 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 4270template <> 4271void 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 4278template <> 4279void 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 4287template <> 4288void 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}. 4303template <> 4304void 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 4316template <> 4317void 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 4325template <> 4326void 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 4358SimplifiedLowering::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 4374void 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 4386void 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 4488void 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 4583Node* 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 4599Node* 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 4615Node* 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 4630Node* 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 4703Node* 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 4801Node* 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 4817Node* 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 4835Node* 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 4895void 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 4906void 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 4917void 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 4927void 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 4936void 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 4945void 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 4962void 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 4979void 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 4995void 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 5006Node* 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 5014Node* 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 5024Node* 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 5032Operator 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 5045Operator 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 5059Operator 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 5072void 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