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