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/base/bits.h" 10 #include "src/code-factory.h" 11 #include "src/compiler/common-operator.h" 12 #include "src/compiler/diamond.h" 13 #include "src/compiler/linkage.h" 14 #include "src/compiler/node-matchers.h" 15 #include "src/compiler/node-properties.h" 16 #include "src/compiler/operator-properties.h" 17 #include "src/compiler/representation-change.h" 18 #include "src/compiler/simplified-operator.h" 19 #include "src/compiler/source-position.h" 20 #include "src/objects.h" 21 #include "src/type-cache.h" 22 23 namespace v8 { 24 namespace internal { 25 namespace compiler { 26 27 // Macro for outputting trace information from representation inference. 28 #define TRACE(...) \ 29 do { \ 30 if (FLAG_trace_representation) PrintF(__VA_ARGS__); \ 31 } while (false) 32 33 // Representation selection and lowering of {Simplified} operators to machine 34 // operators are interwined. We use a fixpoint calculation to compute both the 35 // output representation and the best possible lowering for {Simplified} nodes. 36 // Representation change insertion ensures that all values are in the correct 37 // machine representation after this phase, as dictated by the machine 38 // operators themselves. 39 enum Phase { 40 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information 41 // backwards from uses to definitions, around cycles in phis, according 42 // to local rules for each operator. 43 // During this phase, the usage information for a node determines the best 44 // possible lowering for each operator so far, and that in turn determines 45 // the output representation. 46 // Therefore, to be correct, this phase must iterate to a fixpoint before 47 // the next phase can begin. 48 PROPAGATE, 49 50 // 2.) LOWER: perform lowering for all {Simplified} nodes by replacing some 51 // operators for some nodes, expanding some nodes to multiple nodes, or 52 // removing some (redundant) nodes. 53 // During this phase, use the {RepresentationChanger} to insert 54 // representation changes between uses that demand a particular 55 // representation and nodes that produce a different representation. 56 LOWER 57 }; 58 59 60 namespace { 61 62 // The {UseInfo} class is used to describe a use of an input of a node. 63 // 64 // This information is used in two different ways, based on the phase: 65 // 66 // 1. During propagation, the use info is used to inform the input node 67 // about what part of the input is used (we call this truncation) and what 68 // is the preferred representation. 69 // 70 // 2. During lowering, the use info is used to properly convert the input 71 // to the preferred representation. The preferred representation might be 72 // insufficient to do the conversion (e.g. word32->float64 conv), so we also 73 // need the signedness information to produce the correct value. 74 class UseInfo { 75 public: 76 UseInfo(MachineRepresentation preferred, Truncation truncation) 77 : preferred_(preferred), truncation_(truncation) {} 78 static UseInfo TruncatingWord32() { 79 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32()); 80 } 81 static UseInfo TruncatingWord64() { 82 return UseInfo(MachineRepresentation::kWord64, Truncation::Word64()); 83 } 84 static UseInfo Bool() { 85 return UseInfo(MachineRepresentation::kBit, Truncation::Bool()); 86 } 87 static UseInfo Float32() { 88 return UseInfo(MachineRepresentation::kFloat32, Truncation::Float32()); 89 } 90 static UseInfo Float64() { 91 return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64()); 92 } 93 static UseInfo PointerInt() { 94 return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64(); 95 } 96 static UseInfo AnyTagged() { 97 return UseInfo(MachineRepresentation::kTagged, Truncation::Any()); 98 } 99 100 // Undetermined representation. 101 static UseInfo Any() { 102 return UseInfo(MachineRepresentation::kNone, Truncation::Any()); 103 } 104 static UseInfo None() { 105 return UseInfo(MachineRepresentation::kNone, Truncation::None()); 106 } 107 108 // Truncation to a representation that is smaller than the preferred 109 // one. 110 static UseInfo Float64TruncatingToWord32() { 111 return UseInfo(MachineRepresentation::kFloat64, Truncation::Word32()); 112 } 113 static UseInfo Word64TruncatingToWord32() { 114 return UseInfo(MachineRepresentation::kWord64, Truncation::Word32()); 115 } 116 static UseInfo AnyTruncatingToBool() { 117 return UseInfo(MachineRepresentation::kNone, Truncation::Bool()); 118 } 119 120 MachineRepresentation preferred() const { return preferred_; } 121 Truncation truncation() const { return truncation_; } 122 123 private: 124 MachineRepresentation preferred_; 125 Truncation truncation_; 126 }; 127 128 129 UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) { 130 switch (rep) { 131 case MachineRepresentation::kTagged: 132 return UseInfo::AnyTagged(); 133 case MachineRepresentation::kFloat64: 134 return UseInfo::Float64(); 135 case MachineRepresentation::kFloat32: 136 return UseInfo::Float32(); 137 case MachineRepresentation::kWord64: 138 return UseInfo::TruncatingWord64(); 139 case MachineRepresentation::kWord8: 140 case MachineRepresentation::kWord16: 141 case MachineRepresentation::kWord32: 142 return UseInfo::TruncatingWord32(); 143 case MachineRepresentation::kBit: 144 return UseInfo::Bool(); 145 case MachineRepresentation::kNone: 146 break; 147 } 148 UNREACHABLE(); 149 return UseInfo::None(); 150 } 151 152 153 UseInfo UseInfoForBasePointer(const FieldAccess& access) { 154 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt(); 155 } 156 157 158 UseInfo UseInfoForBasePointer(const ElementAccess& access) { 159 return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::PointerInt(); 160 } 161 162 163 #ifdef DEBUG 164 // Helpers for monotonicity checking. 165 bool MachineRepresentationIsSubtype(MachineRepresentation r1, 166 MachineRepresentation r2) { 167 switch (r1) { 168 case MachineRepresentation::kNone: 169 return true; 170 case MachineRepresentation::kBit: 171 return r2 == MachineRepresentation::kBit || 172 r2 == MachineRepresentation::kTagged; 173 case MachineRepresentation::kWord8: 174 return r2 == MachineRepresentation::kWord8 || 175 r2 == MachineRepresentation::kWord16 || 176 r2 == MachineRepresentation::kWord32 || 177 r2 == MachineRepresentation::kWord64 || 178 r2 == MachineRepresentation::kFloat32 || 179 r2 == MachineRepresentation::kFloat64 || 180 r2 == MachineRepresentation::kTagged; 181 case MachineRepresentation::kWord16: 182 return r2 == MachineRepresentation::kWord16 || 183 r2 == MachineRepresentation::kWord32 || 184 r2 == MachineRepresentation::kWord64 || 185 r2 == MachineRepresentation::kFloat32 || 186 r2 == MachineRepresentation::kFloat64 || 187 r2 == MachineRepresentation::kTagged; 188 case MachineRepresentation::kWord32: 189 return r2 == MachineRepresentation::kWord32 || 190 r2 == MachineRepresentation::kWord64 || 191 r2 == MachineRepresentation::kFloat64 || 192 r2 == MachineRepresentation::kTagged; 193 case MachineRepresentation::kWord64: 194 return r2 == MachineRepresentation::kWord64; 195 case MachineRepresentation::kFloat32: 196 return r2 == MachineRepresentation::kFloat32 || 197 r2 == MachineRepresentation::kFloat64 || 198 r2 == MachineRepresentation::kTagged; 199 case MachineRepresentation::kFloat64: 200 return r2 == MachineRepresentation::kFloat64 || 201 r2 == MachineRepresentation::kTagged; 202 case MachineRepresentation::kTagged: 203 return r2 == MachineRepresentation::kTagged; 204 } 205 UNREACHABLE(); 206 return false; 207 } 208 209 210 class InputUseInfos { 211 public: 212 explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {} 213 214 void SetAndCheckInput(Node* node, int index, UseInfo use_info) { 215 if (input_use_infos_.empty()) { 216 input_use_infos_.resize(node->InputCount(), UseInfo::None()); 217 } 218 // Check that the new use informatin is a super-type of the old 219 // one. 220 CHECK(IsUseLessGeneral(input_use_infos_[index], use_info)); 221 input_use_infos_[index] = use_info; 222 } 223 224 private: 225 ZoneVector<UseInfo> input_use_infos_; 226 227 static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) { 228 return MachineRepresentationIsSubtype(use1.preferred(), use2.preferred()) && 229 use1.truncation().IsLessGeneralThan(use2.truncation()); 230 } 231 }; 232 233 #endif // DEBUG 234 235 } // namespace 236 237 238 class RepresentationSelector { 239 public: 240 // Information for each node tracked during the fixpoint. 241 class NodeOutputInfo { 242 public: 243 NodeOutputInfo(MachineRepresentation representation, Type* type) 244 : type_(type), representation_(representation) {} 245 NodeOutputInfo() 246 : type_(Type::None()), representation_(MachineRepresentation::kNone) {} 247 248 MachineRepresentation representation() const { return representation_; } 249 Type* type() const { return type_; } 250 251 static NodeOutputInfo None() { 252 return NodeOutputInfo(MachineRepresentation::kNone, Type::None()); 253 } 254 255 static NodeOutputInfo Float32() { 256 return NodeOutputInfo(MachineRepresentation::kFloat32, Type::Number()); 257 } 258 259 static NodeOutputInfo Float64() { 260 return NodeOutputInfo(MachineRepresentation::kFloat64, Type::Number()); 261 } 262 263 static NodeOutputInfo NumberTruncatedToWord32() { 264 return NodeOutputInfo(MachineRepresentation::kWord32, Type::Number()); 265 } 266 267 static NodeOutputInfo Int32() { 268 return NodeOutputInfo(MachineRepresentation::kWord32, Type::Signed32()); 269 } 270 271 static NodeOutputInfo Uint32() { 272 return NodeOutputInfo(MachineRepresentation::kWord32, Type::Unsigned32()); 273 } 274 275 static NodeOutputInfo Bool() { 276 return NodeOutputInfo(MachineRepresentation::kBit, Type::Boolean()); 277 } 278 279 static NodeOutputInfo Int64() { 280 // TODO(jarin) Fix once we have a real int64 type. 281 return NodeOutputInfo(MachineRepresentation::kWord64, Type::Internal()); 282 } 283 284 static NodeOutputInfo Uint64() { 285 // TODO(jarin) Fix once we have a real uint64 type. 286 return NodeOutputInfo(MachineRepresentation::kWord64, Type::Internal()); 287 } 288 289 static NodeOutputInfo AnyTagged() { 290 return NodeOutputInfo(MachineRepresentation::kTagged, Type::Any()); 291 } 292 293 static NodeOutputInfo NumberTagged() { 294 return NodeOutputInfo(MachineRepresentation::kTagged, Type::Number()); 295 } 296 297 static NodeOutputInfo Pointer() { 298 return NodeOutputInfo(MachineType::PointerRepresentation(), Type::Any()); 299 } 300 301 private: 302 Type* type_; 303 MachineRepresentation representation_; 304 }; 305 306 class NodeInfo { 307 public: 308 // Adds new use to the node. Returns true if something has changed 309 // and the node has to be requeued. 310 bool AddUse(UseInfo info) { 311 Truncation old_truncation = truncation_; 312 truncation_ = Truncation::Generalize(truncation_, info.truncation()); 313 return truncation_ != old_truncation; 314 } 315 316 void set_queued(bool value) { queued_ = value; } 317 bool queued() const { return queued_; } 318 void set_visited() { visited_ = true; } 319 bool visited() const { return visited_; } 320 Truncation truncation() const { return truncation_; } 321 void set_output_type(NodeOutputInfo output) { output_ = output; } 322 323 Type* output_type() const { return output_.type(); } 324 MachineRepresentation representation() const { 325 return output_.representation(); 326 } 327 328 private: 329 bool queued_ = false; // Bookkeeping for the traversal. 330 bool visited_ = false; // Bookkeeping for the traversal. 331 NodeOutputInfo output_; // Output type and representation. 332 Truncation truncation_ = Truncation::None(); // Information about uses. 333 }; 334 335 RepresentationSelector(JSGraph* jsgraph, Zone* zone, 336 RepresentationChanger* changer, 337 SourcePositionTable* source_positions) 338 : jsgraph_(jsgraph), 339 count_(jsgraph->graph()->NodeCount()), 340 info_(count_, zone), 341 #ifdef DEBUG 342 node_input_use_infos_(count_, InputUseInfos(zone), zone), 343 #endif 344 nodes_(zone), 345 replacements_(zone), 346 phase_(PROPAGATE), 347 changer_(changer), 348 queue_(zone), 349 source_positions_(source_positions), 350 type_cache_(TypeCache::Get()) { 351 } 352 353 void Run(SimplifiedLowering* lowering) { 354 // Run propagation phase to a fixpoint. 355 TRACE("--{Propagation phase}--\n"); 356 phase_ = PROPAGATE; 357 EnqueueInitial(jsgraph_->graph()->end()); 358 // Process nodes from the queue until it is empty. 359 while (!queue_.empty()) { 360 Node* node = queue_.front(); 361 NodeInfo* info = GetInfo(node); 362 queue_.pop(); 363 info->set_queued(false); 364 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic()); 365 VisitNode(node, info->truncation(), nullptr); 366 TRACE(" ==> output "); 367 PrintOutputInfo(info); 368 TRACE("\n"); 369 } 370 371 // Run lowering and change insertion phase. 372 TRACE("--{Simplified lowering phase}--\n"); 373 phase_ = LOWER; 374 // Process nodes from the collected {nodes_} vector. 375 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) { 376 Node* node = *i; 377 NodeInfo* info = GetInfo(node); 378 TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic()); 379 // Reuse {VisitNode()} so the representation rules are in one place. 380 SourcePositionTable::Scope scope( 381 source_positions_, source_positions_->GetSourcePosition(node)); 382 VisitNode(node, info->truncation(), lowering); 383 } 384 385 // Perform the final replacements. 386 for (NodeVector::iterator i = replacements_.begin(); 387 i != replacements_.end(); ++i) { 388 Node* node = *i; 389 Node* replacement = *(++i); 390 node->ReplaceUses(replacement); 391 // We also need to replace the node in the rest of the vector. 392 for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) { 393 ++j; 394 if (*j == node) *j = replacement; 395 } 396 } 397 } 398 399 void EnqueueInitial(Node* node) { 400 NodeInfo* info = GetInfo(node); 401 info->set_visited(); 402 info->set_queued(true); 403 nodes_.push_back(node); 404 queue_.push(node); 405 } 406 407 // Enqueue {use_node}'s {index} input if the {use} contains new information 408 // for that input node. Add the input to {nodes_} if this is the first time 409 // it's been visited. 410 void EnqueueInput(Node* use_node, int index, 411 UseInfo use_info = UseInfo::None()) { 412 Node* node = use_node->InputAt(index); 413 if (phase_ != PROPAGATE) return; 414 NodeInfo* info = GetInfo(node); 415 #ifdef DEBUG 416 // Check monotonicity of input requirements. 417 node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index, 418 use_info); 419 #endif // DEBUG 420 if (!info->visited()) { 421 // First visit of this node. 422 info->set_visited(); 423 info->set_queued(true); 424 nodes_.push_back(node); 425 queue_.push(node); 426 TRACE(" initial: "); 427 info->AddUse(use_info); 428 PrintTruncation(info->truncation()); 429 return; 430 } 431 TRACE(" queue?: "); 432 PrintTruncation(info->truncation()); 433 if (info->AddUse(use_info)) { 434 // New usage information for the node is available. 435 if (!info->queued()) { 436 queue_.push(node); 437 info->set_queued(true); 438 TRACE(" added: "); 439 } else { 440 TRACE(" inqueue: "); 441 } 442 PrintTruncation(info->truncation()); 443 } 444 } 445 446 bool lower() { return phase_ == LOWER; } 447 448 void EnqueueUses(Node* node) { 449 for (Edge edge : node->use_edges()) { 450 if (NodeProperties::IsValueEdge(edge)) { 451 Node* const user = edge.from(); 452 if (user->id() < count_) { 453 // New type information for the node is available. 454 NodeInfo* info = GetInfo(user); 455 // Enqueue the node only if we are sure it is reachable from 456 // the end and it has not been queued yet. 457 if (info->visited() && !info->queued()) { 458 queue_.push(user); 459 info->set_queued(true); 460 } 461 } 462 } 463 } 464 } 465 466 void SetOutputFromMachineType(Node* node, MachineType machine_type) { 467 Type* type = Type::None(); 468 switch (machine_type.semantic()) { 469 case MachineSemantic::kNone: 470 type = Type::None(); 471 break; 472 case MachineSemantic::kBool: 473 type = Type::Boolean(); 474 break; 475 case MachineSemantic::kInt32: 476 type = Type::Signed32(); 477 break; 478 case MachineSemantic::kUint32: 479 type = Type::Unsigned32(); 480 break; 481 case MachineSemantic::kInt64: 482 // TODO(jarin) Fix once we have proper int64. 483 type = Type::Internal(); 484 break; 485 case MachineSemantic::kUint64: 486 // TODO(jarin) Fix once we have proper uint64. 487 type = Type::Internal(); 488 break; 489 case MachineSemantic::kNumber: 490 type = Type::Number(); 491 break; 492 case MachineSemantic::kAny: 493 type = Type::Any(); 494 break; 495 } 496 return SetOutput(node, NodeOutputInfo(machine_type.representation(), type)); 497 } 498 499 void SetOutput(Node* node, NodeOutputInfo output_info) { 500 // Every node should have at most one output representation. Note that 501 // phis can have 0, if they have not been used in a representation-inducing 502 // instruction. 503 Type* output_type = output_info.type(); 504 if (NodeProperties::IsTyped(node)) { 505 output_type = Type::Intersect(NodeProperties::GetType(node), 506 output_info.type(), jsgraph_->zone()); 507 } 508 NodeInfo* info = GetInfo(node); 509 DCHECK(info->output_type()->Is(output_type)); 510 DCHECK(MachineRepresentationIsSubtype(info->representation(), 511 output_info.representation())); 512 if (!output_type->Is(info->output_type()) || 513 output_info.representation() != info->representation()) { 514 EnqueueUses(node); 515 } 516 info->set_output_type( 517 NodeOutputInfo(output_info.representation(), output_type)); 518 } 519 520 bool BothInputsAreSigned32(Node* node) { 521 DCHECK_EQ(2, node->InputCount()); 522 return GetInfo(node->InputAt(0))->output_type()->Is(Type::Signed32()) && 523 GetInfo(node->InputAt(1))->output_type()->Is(Type::Signed32()); 524 } 525 526 bool BothInputsAreUnsigned32(Node* node) { 527 DCHECK_EQ(2, node->InputCount()); 528 return GetInfo(node->InputAt(0))->output_type()->Is(Type::Unsigned32()) && 529 GetInfo(node->InputAt(1))->output_type()->Is(Type::Unsigned32()); 530 } 531 532 bool BothInputsAre(Node* node, Type* type) { 533 DCHECK_EQ(2, node->InputCount()); 534 return GetInfo(node->InputAt(0))->output_type()->Is(type) && 535 GetInfo(node->InputAt(1))->output_type()->Is(type); 536 } 537 538 void ConvertInput(Node* node, int index, UseInfo use) { 539 Node* input = node->InputAt(index); 540 // In the change phase, insert a change before the use if necessary. 541 if (use.preferred() == MachineRepresentation::kNone) 542 return; // No input requirement on the use. 543 NodeInfo* input_info = GetInfo(input); 544 MachineRepresentation input_rep = input_info->representation(); 545 if (input_rep != use.preferred()) { 546 // Output representation doesn't match usage. 547 TRACE(" change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(), 548 index, input->id(), input->op()->mnemonic()); 549 TRACE(" from "); 550 PrintOutputInfo(input_info); 551 TRACE(" to "); 552 PrintUseInfo(use); 553 TRACE("\n"); 554 Node* n = changer_->GetRepresentationFor( 555 input, input_info->representation(), input_info->output_type(), 556 use.preferred(), use.truncation()); 557 node->ReplaceInput(index, n); 558 } 559 } 560 561 void ProcessInput(Node* node, int index, UseInfo use) { 562 if (phase_ == PROPAGATE) { 563 EnqueueInput(node, index, use); 564 } else { 565 ConvertInput(node, index, use); 566 } 567 } 568 569 void ProcessRemainingInputs(Node* node, int index) { 570 DCHECK_GE(index, NodeProperties::PastValueIndex(node)); 571 DCHECK_GE(index, NodeProperties::PastContextIndex(node)); 572 for (int i = std::max(index, NodeProperties::FirstEffectIndex(node)); 573 i < NodeProperties::PastEffectIndex(node); ++i) { 574 EnqueueInput(node, i); // Effect inputs: just visit 575 } 576 for (int i = std::max(index, NodeProperties::FirstControlIndex(node)); 577 i < NodeProperties::PastControlIndex(node); ++i) { 578 EnqueueInput(node, i); // Control inputs: just visit 579 } 580 } 581 582 // The default, most general visitation case. For {node}, process all value, 583 // context, frame state, effect, and control inputs, assuming that value 584 // inputs should have {kRepTagged} representation and can observe all output 585 // values {kTypeAny}. 586 void VisitInputs(Node* node) { 587 int tagged_count = node->op()->ValueInputCount() + 588 OperatorProperties::GetContextInputCount(node->op()); 589 // Visit value and context inputs as tagged. 590 for (int i = 0; i < tagged_count; i++) { 591 ProcessInput(node, i, UseInfo::AnyTagged()); 592 } 593 // Only enqueue other inputs (framestates, effects, control). 594 for (int i = tagged_count; i < node->InputCount(); i++) { 595 EnqueueInput(node, i); 596 } 597 } 598 599 // Helper for binops of the R x L -> O variety. 600 void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use, 601 NodeOutputInfo output) { 602 DCHECK_EQ(2, node->op()->ValueInputCount()); 603 ProcessInput(node, 0, left_use); 604 ProcessInput(node, 1, right_use); 605 for (int i = 2; i < node->InputCount(); i++) { 606 EnqueueInput(node, i); 607 } 608 SetOutput(node, output); 609 } 610 611 // Helper for binops of the I x I -> O variety. 612 void VisitBinop(Node* node, UseInfo input_use, NodeOutputInfo output) { 613 VisitBinop(node, input_use, input_use, output); 614 } 615 616 // Helper for unops of the I -> O variety. 617 void VisitUnop(Node* node, UseInfo input_use, NodeOutputInfo output) { 618 DCHECK_EQ(1, node->InputCount()); 619 ProcessInput(node, 0, input_use); 620 SetOutput(node, output); 621 } 622 623 // Helper for leaf nodes. 624 void VisitLeaf(Node* node, NodeOutputInfo output) { 625 DCHECK_EQ(0, node->InputCount()); 626 SetOutput(node, output); 627 } 628 629 // Helpers for specific types of binops. 630 void VisitFloat64Binop(Node* node) { 631 VisitBinop(node, UseInfo::Float64(), NodeOutputInfo::Float64()); 632 } 633 void VisitInt32Binop(Node* node) { 634 VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32()); 635 } 636 void VisitWord32TruncatingBinop(Node* node) { 637 VisitBinop(node, UseInfo::TruncatingWord32(), 638 NodeOutputInfo::NumberTruncatedToWord32()); 639 } 640 void VisitUint32Binop(Node* node) { 641 VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32()); 642 } 643 void VisitInt64Binop(Node* node) { 644 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Int64()); 645 } 646 void VisitUint64Binop(Node* node) { 647 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Uint64()); 648 } 649 void VisitFloat64Cmp(Node* node) { 650 VisitBinop(node, UseInfo::Float64(), NodeOutputInfo::Bool()); 651 } 652 void VisitInt32Cmp(Node* node) { 653 VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool()); 654 } 655 void VisitUint32Cmp(Node* node) { 656 VisitBinop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Bool()); 657 } 658 void VisitInt64Cmp(Node* node) { 659 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool()); 660 } 661 void VisitUint64Cmp(Node* node) { 662 VisitBinop(node, UseInfo::TruncatingWord64(), NodeOutputInfo::Bool()); 663 } 664 665 // Infer representation for phi-like nodes. 666 NodeOutputInfo GetOutputInfoForPhi(Node* node, Truncation use) { 667 // Compute the type. 668 Type* type = GetInfo(node->InputAt(0))->output_type(); 669 for (int i = 1; i < node->op()->ValueInputCount(); ++i) { 670 type = Type::Union(type, GetInfo(node->InputAt(i))->output_type(), 671 jsgraph_->zone()); 672 } 673 674 // Compute the representation. 675 MachineRepresentation rep = MachineRepresentation::kTagged; 676 if (type->Is(Type::None())) { 677 rep = MachineRepresentation::kNone; 678 } else if (type->Is(Type::Signed32()) || type->Is(Type::Unsigned32())) { 679 rep = MachineRepresentation::kWord32; 680 } else if (use.TruncatesToWord32()) { 681 rep = MachineRepresentation::kWord32; 682 } else if (type->Is(Type::Boolean())) { 683 rep = MachineRepresentation::kBit; 684 } else if (type->Is(Type::Number())) { 685 rep = MachineRepresentation::kFloat64; 686 } else if (type->Is(Type::Internal())) { 687 // We mark (u)int64 as Type::Internal. 688 // TODO(jarin) This is a workaround for our lack of (u)int64 689 // types. This can be removed once we can represent (u)int64 690 // unambiguously. (At the moment internal objects, such as the hole, 691 // are also Type::Internal()). 692 bool is_word64 = GetInfo(node->InputAt(0))->representation() == 693 MachineRepresentation::kWord64; 694 #ifdef DEBUG 695 // Check that all the inputs agree on being Word64. 696 for (int i = 1; i < node->op()->ValueInputCount(); i++) { 697 DCHECK_EQ(is_word64, GetInfo(node->InputAt(i))->representation() == 698 MachineRepresentation::kWord64); 699 } 700 #endif 701 rep = is_word64 ? MachineRepresentation::kWord64 702 : MachineRepresentation::kTagged; 703 } 704 return NodeOutputInfo(rep, type); 705 } 706 707 // Helper for handling selects. 708 void VisitSelect(Node* node, Truncation truncation, 709 SimplifiedLowering* lowering) { 710 ProcessInput(node, 0, UseInfo::Bool()); 711 712 NodeOutputInfo output = GetOutputInfoForPhi(node, truncation); 713 SetOutput(node, output); 714 715 if (lower()) { 716 // Update the select operator. 717 SelectParameters p = SelectParametersOf(node->op()); 718 if (output.representation() != p.representation()) { 719 NodeProperties::ChangeOp(node, lowering->common()->Select( 720 output.representation(), p.hint())); 721 } 722 } 723 // Convert inputs to the output representation of this phi, pass the 724 // truncation truncation along. 725 UseInfo input_use(output.representation(), truncation); 726 ProcessInput(node, 1, input_use); 727 ProcessInput(node, 2, input_use); 728 } 729 730 // Helper for handling phis. 731 void VisitPhi(Node* node, Truncation truncation, 732 SimplifiedLowering* lowering) { 733 NodeOutputInfo output = GetOutputInfoForPhi(node, truncation); 734 SetOutput(node, output); 735 736 int values = node->op()->ValueInputCount(); 737 if (lower()) { 738 // Update the phi operator. 739 if (output.representation() != PhiRepresentationOf(node->op())) { 740 NodeProperties::ChangeOp( 741 node, lowering->common()->Phi(output.representation(), values)); 742 } 743 } 744 745 // Convert inputs to the output representation of this phi, pass the 746 // truncation truncation along. 747 UseInfo input_use(output.representation(), truncation); 748 for (int i = 0; i < node->InputCount(); i++) { 749 ProcessInput(node, i, i < values ? input_use : UseInfo::None()); 750 } 751 } 752 753 void VisitCall(Node* node, SimplifiedLowering* lowering) { 754 const CallDescriptor* desc = OpParameter<const CallDescriptor*>(node->op()); 755 const MachineSignature* sig = desc->GetMachineSignature(); 756 int params = static_cast<int>(sig->parameter_count()); 757 // Propagate representation information from call descriptor. 758 for (int i = 0; i < node->InputCount(); i++) { 759 if (i == 0) { 760 // The target of the call. 761 ProcessInput(node, i, UseInfo::None()); 762 } else if ((i - 1) < params) { 763 ProcessInput(node, i, TruncatingUseInfoFromRepresentation( 764 sig->GetParam(i - 1).representation())); 765 } else { 766 ProcessInput(node, i, UseInfo::None()); 767 } 768 } 769 770 if (sig->return_count() > 0) { 771 SetOutputFromMachineType(node, desc->GetMachineSignature()->GetReturn()); 772 } else { 773 SetOutput(node, NodeOutputInfo::AnyTagged()); 774 } 775 } 776 777 MachineSemantic DeoptValueSemanticOf(Type* type) { 778 CHECK(!type->Is(Type::None())); 779 // We only need signedness to do deopt correctly. 780 if (type->Is(Type::Signed32())) { 781 return MachineSemantic::kInt32; 782 } else if (type->Is(Type::Unsigned32())) { 783 return MachineSemantic::kUint32; 784 } else { 785 return MachineSemantic::kAny; 786 } 787 } 788 789 void VisitStateValues(Node* node) { 790 if (phase_ == PROPAGATE) { 791 for (int i = 0; i < node->InputCount(); i++) { 792 EnqueueInput(node, i, UseInfo::Any()); 793 } 794 } else { 795 Zone* zone = jsgraph_->zone(); 796 ZoneVector<MachineType>* types = 797 new (zone->New(sizeof(ZoneVector<MachineType>))) 798 ZoneVector<MachineType>(node->InputCount(), zone); 799 for (int i = 0; i < node->InputCount(); i++) { 800 NodeInfo* input_info = GetInfo(node->InputAt(i)); 801 MachineType machine_type( 802 input_info->representation(), 803 DeoptValueSemanticOf(input_info->output_type())); 804 DCHECK(machine_type.representation() != 805 MachineRepresentation::kWord32 || 806 machine_type.semantic() == MachineSemantic::kInt32 || 807 machine_type.semantic() == MachineSemantic::kUint32); 808 (*types)[i] = machine_type; 809 } 810 NodeProperties::ChangeOp(node, 811 jsgraph_->common()->TypedStateValues(types)); 812 } 813 SetOutput(node, NodeOutputInfo::AnyTagged()); 814 } 815 816 const Operator* Int32Op(Node* node) { 817 return changer_->Int32OperatorFor(node->opcode()); 818 } 819 820 const Operator* Uint32Op(Node* node) { 821 return changer_->Uint32OperatorFor(node->opcode()); 822 } 823 824 const Operator* Float64Op(Node* node) { 825 return changer_->Float64OperatorFor(node->opcode()); 826 } 827 828 // Dispatching routine for visiting the node {node} with the usage {use}. 829 // Depending on the operator, propagate new usage info to the inputs. 830 void VisitNode(Node* node, Truncation truncation, 831 SimplifiedLowering* lowering) { 832 switch (node->opcode()) { 833 //------------------------------------------------------------------ 834 // Common operators. 835 //------------------------------------------------------------------ 836 case IrOpcode::kStart: 837 case IrOpcode::kDead: 838 return VisitLeaf(node, NodeOutputInfo::None()); 839 case IrOpcode::kParameter: { 840 // TODO(titzer): use representation from linkage. 841 Type* type = NodeProperties::GetType(node); 842 ProcessInput(node, 0, UseInfo::None()); 843 SetOutput(node, NodeOutputInfo(MachineRepresentation::kTagged, type)); 844 return; 845 } 846 case IrOpcode::kInt32Constant: 847 return VisitLeaf(node, NodeOutputInfo::Int32()); 848 case IrOpcode::kInt64Constant: 849 return VisitLeaf(node, NodeOutputInfo::Int64()); 850 case IrOpcode::kFloat32Constant: 851 return VisitLeaf(node, NodeOutputInfo::Float32()); 852 case IrOpcode::kFloat64Constant: 853 return VisitLeaf(node, NodeOutputInfo::Float64()); 854 case IrOpcode::kExternalConstant: 855 return VisitLeaf(node, NodeOutputInfo::Pointer()); 856 case IrOpcode::kNumberConstant: 857 return VisitLeaf(node, NodeOutputInfo::NumberTagged()); 858 case IrOpcode::kHeapConstant: 859 return VisitLeaf(node, NodeOutputInfo::AnyTagged()); 860 861 case IrOpcode::kBranch: 862 ProcessInput(node, 0, UseInfo::Bool()); 863 EnqueueInput(node, NodeProperties::FirstControlIndex(node)); 864 break; 865 case IrOpcode::kSwitch: 866 ProcessInput(node, 0, UseInfo::TruncatingWord32()); 867 EnqueueInput(node, NodeProperties::FirstControlIndex(node)); 868 break; 869 case IrOpcode::kSelect: 870 return VisitSelect(node, truncation, lowering); 871 case IrOpcode::kPhi: 872 return VisitPhi(node, truncation, lowering); 873 case IrOpcode::kCall: 874 return VisitCall(node, lowering); 875 876 //------------------------------------------------------------------ 877 // JavaScript operators. 878 //------------------------------------------------------------------ 879 // For now, we assume that all JS operators were too complex to lower 880 // to Simplified and that they will always require tagged value inputs 881 // and produce tagged value outputs. 882 // TODO(turbofan): it might be possible to lower some JSOperators here, 883 // but that responsibility really lies in the typed lowering phase. 884 #define DEFINE_JS_CASE(x) case IrOpcode::k##x: 885 JS_OP_LIST(DEFINE_JS_CASE) 886 #undef DEFINE_JS_CASE 887 VisitInputs(node); 888 return SetOutput(node, NodeOutputInfo::AnyTagged()); 889 890 //------------------------------------------------------------------ 891 // Simplified operators. 892 //------------------------------------------------------------------ 893 case IrOpcode::kBooleanNot: { 894 if (lower()) { 895 NodeInfo* input_info = GetInfo(node->InputAt(0)); 896 if (input_info->representation() == MachineRepresentation::kBit) { 897 // BooleanNot(x: kRepBit) => Word32Equal(x, #0) 898 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0)); 899 NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal()); 900 } else { 901 // BooleanNot(x: kRepTagged) => WordEqual(x, #false) 902 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant()); 903 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); 904 } 905 } else { 906 // No input representation requirement; adapt during lowering. 907 ProcessInput(node, 0, UseInfo::AnyTruncatingToBool()); 908 SetOutput(node, NodeOutputInfo::Bool()); 909 } 910 break; 911 } 912 case IrOpcode::kBooleanToNumber: { 913 if (lower()) { 914 NodeInfo* input_info = GetInfo(node->InputAt(0)); 915 if (input_info->representation() == MachineRepresentation::kBit) { 916 // BooleanToNumber(x: kRepBit) => x 917 DeferReplacement(node, node->InputAt(0)); 918 } else { 919 // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true) 920 node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant()); 921 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); 922 } 923 } else { 924 // No input representation requirement; adapt during lowering. 925 ProcessInput(node, 0, UseInfo::AnyTruncatingToBool()); 926 SetOutput(node, NodeOutputInfo::Int32()); 927 } 928 break; 929 } 930 case IrOpcode::kNumberEqual: 931 case IrOpcode::kNumberLessThan: 932 case IrOpcode::kNumberLessThanOrEqual: { 933 // Number comparisons reduce to integer comparisons for integer inputs. 934 if (BothInputsAreSigned32(node)) { 935 // => signed Int32Cmp 936 VisitInt32Cmp(node); 937 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); 938 } else if (BothInputsAreUnsigned32(node)) { 939 // => unsigned Int32Cmp 940 VisitUint32Cmp(node); 941 if (lower()) NodeProperties::ChangeOp(node, Uint32Op(node)); 942 } else { 943 // => Float64Cmp 944 VisitFloat64Cmp(node); 945 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); 946 } 947 break; 948 } 949 case IrOpcode::kNumberAdd: 950 case IrOpcode::kNumberSubtract: { 951 if (BothInputsAre(node, Type::Signed32()) && 952 NodeProperties::GetType(node)->Is(Type::Signed32())) { 953 // int32 + int32 = int32 954 // => signed Int32Add/Sub 955 VisitInt32Binop(node); 956 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); 957 } else if (BothInputsAre(node, type_cache_.kAdditiveSafeInteger) && 958 truncation.TruncatesToWord32()) { 959 // safe-int + safe-int = x (truncated to int32) 960 // => signed Int32Add/Sub (truncated) 961 VisitWord32TruncatingBinop(node); 962 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); 963 } else { 964 // => Float64Add/Sub 965 VisitFloat64Binop(node); 966 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); 967 } 968 break; 969 } 970 case IrOpcode::kNumberMultiply: { 971 if (BothInputsAreSigned32(node)) { 972 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { 973 // Multiply reduces to Int32Mul if the inputs and the output 974 // are integers. 975 VisitInt32Binop(node); 976 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); 977 break; 978 } 979 if (truncation.TruncatesToWord32() && 980 NodeProperties::GetType(node)->Is(type_cache_.kSafeInteger)) { 981 // Multiply reduces to Int32Mul if the inputs are integers, 982 // the uses are truncating and the result is in the safe 983 // integer range. 984 VisitWord32TruncatingBinop(node); 985 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); 986 break; 987 } 988 } 989 // => Float64Mul 990 VisitFloat64Binop(node); 991 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); 992 break; 993 } 994 case IrOpcode::kNumberDivide: { 995 if (BothInputsAreSigned32(node)) { 996 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { 997 // => signed Int32Div 998 VisitInt32Binop(node); 999 if (lower()) DeferReplacement(node, lowering->Int32Div(node)); 1000 break; 1001 } 1002 if (truncation.TruncatesToWord32()) { 1003 // => signed Int32Div 1004 VisitWord32TruncatingBinop(node); 1005 if (lower()) DeferReplacement(node, lowering->Int32Div(node)); 1006 break; 1007 } 1008 } 1009 if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) { 1010 // => unsigned Uint32Div 1011 VisitWord32TruncatingBinop(node); 1012 if (lower()) DeferReplacement(node, lowering->Uint32Div(node)); 1013 break; 1014 } 1015 // => Float64Div 1016 VisitFloat64Binop(node); 1017 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); 1018 break; 1019 } 1020 case IrOpcode::kNumberModulus: { 1021 if (BothInputsAreSigned32(node)) { 1022 if (NodeProperties::GetType(node)->Is(Type::Signed32())) { 1023 // => signed Int32Mod 1024 VisitInt32Binop(node); 1025 if (lower()) DeferReplacement(node, lowering->Int32Mod(node)); 1026 break; 1027 } 1028 if (truncation.TruncatesToWord32()) { 1029 // => signed Int32Mod 1030 VisitWord32TruncatingBinop(node); 1031 if (lower()) DeferReplacement(node, lowering->Int32Mod(node)); 1032 break; 1033 } 1034 } 1035 if (BothInputsAreUnsigned32(node) && truncation.TruncatesToWord32()) { 1036 // => unsigned Uint32Mod 1037 VisitWord32TruncatingBinop(node); 1038 if (lower()) DeferReplacement(node, lowering->Uint32Mod(node)); 1039 break; 1040 } 1041 // => Float64Mod 1042 VisitFloat64Binop(node); 1043 if (lower()) NodeProperties::ChangeOp(node, Float64Op(node)); 1044 break; 1045 } 1046 case IrOpcode::kNumberBitwiseOr: 1047 case IrOpcode::kNumberBitwiseXor: 1048 case IrOpcode::kNumberBitwiseAnd: { 1049 VisitInt32Binop(node); 1050 if (lower()) NodeProperties::ChangeOp(node, Int32Op(node)); 1051 break; 1052 } 1053 case IrOpcode::kNumberShiftLeft: { 1054 Type* rhs_type = GetInfo(node->InputAt(1))->output_type(); 1055 VisitBinop(node, UseInfo::TruncatingWord32(), 1056 UseInfo::TruncatingWord32(), NodeOutputInfo::Int32()); 1057 if (lower()) { 1058 lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type); 1059 } 1060 break; 1061 } 1062 case IrOpcode::kNumberShiftRight: { 1063 Type* rhs_type = GetInfo(node->InputAt(1))->output_type(); 1064 VisitBinop(node, UseInfo::TruncatingWord32(), 1065 UseInfo::TruncatingWord32(), NodeOutputInfo::Int32()); 1066 if (lower()) { 1067 lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type); 1068 } 1069 break; 1070 } 1071 case IrOpcode::kNumberShiftRightLogical: { 1072 Type* rhs_type = GetInfo(node->InputAt(1))->output_type(); 1073 VisitBinop(node, UseInfo::TruncatingWord32(), 1074 UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32()); 1075 if (lower()) { 1076 lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type); 1077 } 1078 break; 1079 } 1080 case IrOpcode::kNumberToInt32: { 1081 // Just change representation if necessary. 1082 VisitUnop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Int32()); 1083 if (lower()) DeferReplacement(node, node->InputAt(0)); 1084 break; 1085 } 1086 case IrOpcode::kNumberToUint32: { 1087 // Just change representation if necessary. 1088 VisitUnop(node, UseInfo::TruncatingWord32(), NodeOutputInfo::Uint32()); 1089 if (lower()) DeferReplacement(node, node->InputAt(0)); 1090 break; 1091 } 1092 case IrOpcode::kNumberIsHoleNaN: { 1093 VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Bool()); 1094 if (lower()) { 1095 // NumberIsHoleNaN(x) => Word32Equal(Float64ExtractLowWord32(x), 1096 // #HoleNaNLower32) 1097 node->ReplaceInput(0, 1098 jsgraph_->graph()->NewNode( 1099 lowering->machine()->Float64ExtractLowWord32(), 1100 node->InputAt(0))); 1101 node->AppendInput(jsgraph_->zone(), 1102 jsgraph_->Int32Constant(kHoleNanLower32)); 1103 NodeProperties::ChangeOp(node, jsgraph_->machine()->Word32Equal()); 1104 } 1105 break; 1106 } 1107 case IrOpcode::kPlainPrimitiveToNumber: { 1108 VisitUnop(node, UseInfo::AnyTagged(), NodeOutputInfo::NumberTagged()); 1109 if (lower()) { 1110 // PlainPrimitiveToNumber(x) => Call(ToNumberStub, x, no-context) 1111 Operator::Properties properties = node->op()->properties(); 1112 Callable callable = CodeFactory::ToNumber(jsgraph_->isolate()); 1113 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 1114 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1115 jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0, 1116 flags, properties); 1117 node->InsertInput(jsgraph_->zone(), 0, 1118 jsgraph_->HeapConstant(callable.code())); 1119 node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant()); 1120 NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc)); 1121 } 1122 break; 1123 } 1124 case IrOpcode::kReferenceEqual: { 1125 VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool()); 1126 if (lower()) { 1127 NodeProperties::ChangeOp(node, lowering->machine()->WordEqual()); 1128 } 1129 break; 1130 } 1131 case IrOpcode::kStringEqual: { 1132 VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool()); 1133 if (lower()) lowering->DoStringEqual(node); 1134 break; 1135 } 1136 case IrOpcode::kStringLessThan: { 1137 VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool()); 1138 if (lower()) lowering->DoStringLessThan(node); 1139 break; 1140 } 1141 case IrOpcode::kStringLessThanOrEqual: { 1142 VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool()); 1143 if (lower()) lowering->DoStringLessThanOrEqual(node); 1144 break; 1145 } 1146 case IrOpcode::kAllocate: { 1147 ProcessInput(node, 0, UseInfo::AnyTagged()); 1148 ProcessRemainingInputs(node, 1); 1149 SetOutput(node, NodeOutputInfo::AnyTagged()); 1150 break; 1151 } 1152 case IrOpcode::kLoadField: { 1153 FieldAccess access = FieldAccessOf(node->op()); 1154 ProcessInput(node, 0, UseInfoForBasePointer(access)); 1155 ProcessRemainingInputs(node, 1); 1156 SetOutputFromMachineType(node, access.machine_type); 1157 break; 1158 } 1159 case IrOpcode::kStoreField: { 1160 FieldAccess access = FieldAccessOf(node->op()); 1161 ProcessInput(node, 0, UseInfoForBasePointer(access)); 1162 ProcessInput(node, 1, TruncatingUseInfoFromRepresentation( 1163 access.machine_type.representation())); 1164 ProcessRemainingInputs(node, 2); 1165 SetOutput(node, NodeOutputInfo::None()); 1166 break; 1167 } 1168 case IrOpcode::kLoadBuffer: { 1169 BufferAccess access = BufferAccessOf(node->op()); 1170 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer 1171 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset 1172 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length 1173 ProcessRemainingInputs(node, 3); 1174 1175 NodeOutputInfo output_info; 1176 if (truncation.TruncatesUndefinedToZeroOrNaN()) { 1177 if (truncation.TruncatesNaNToZero()) { 1178 // If undefined is truncated to a non-NaN number, we can use 1179 // the load's representation. 1180 output_info = NodeOutputInfo(access.machine_type().representation(), 1181 NodeProperties::GetType(node)); 1182 } else { 1183 // If undefined is truncated to a number, but the use can 1184 // observe NaN, we need to output at least the float32 1185 // representation. 1186 if (access.machine_type().representation() == 1187 MachineRepresentation::kFloat32) { 1188 output_info = 1189 NodeOutputInfo(access.machine_type().representation(), 1190 NodeProperties::GetType(node)); 1191 } else { 1192 output_info = NodeOutputInfo::Float64(); 1193 } 1194 } 1195 } else { 1196 // If undefined is not truncated away, we need to have the tagged 1197 // representation. 1198 output_info = NodeOutputInfo::AnyTagged(); 1199 } 1200 SetOutput(node, output_info); 1201 if (lower()) 1202 lowering->DoLoadBuffer(node, output_info.representation(), changer_); 1203 break; 1204 } 1205 case IrOpcode::kStoreBuffer: { 1206 BufferAccess access = BufferAccessOf(node->op()); 1207 ProcessInput(node, 0, UseInfo::PointerInt()); // buffer 1208 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // offset 1209 ProcessInput(node, 2, UseInfo::TruncatingWord32()); // length 1210 ProcessInput(node, 3, 1211 TruncatingUseInfoFromRepresentation( 1212 access.machine_type().representation())); // value 1213 ProcessRemainingInputs(node, 4); 1214 SetOutput(node, NodeOutputInfo::None()); 1215 if (lower()) lowering->DoStoreBuffer(node); 1216 break; 1217 } 1218 case IrOpcode::kLoadElement: { 1219 ElementAccess access = ElementAccessOf(node->op()); 1220 ProcessInput(node, 0, UseInfoForBasePointer(access)); // base 1221 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index 1222 ProcessRemainingInputs(node, 2); 1223 SetOutputFromMachineType(node, access.machine_type); 1224 break; 1225 } 1226 case IrOpcode::kStoreElement: { 1227 ElementAccess access = ElementAccessOf(node->op()); 1228 ProcessInput(node, 0, UseInfoForBasePointer(access)); // base 1229 ProcessInput(node, 1, UseInfo::TruncatingWord32()); // index 1230 ProcessInput(node, 2, 1231 TruncatingUseInfoFromRepresentation( 1232 access.machine_type.representation())); // value 1233 ProcessRemainingInputs(node, 3); 1234 SetOutput(node, NodeOutputInfo::None()); 1235 break; 1236 } 1237 case IrOpcode::kObjectIsNumber: { 1238 ProcessInput(node, 0, UseInfo::AnyTagged()); 1239 SetOutput(node, NodeOutputInfo::Bool()); 1240 if (lower()) lowering->DoObjectIsNumber(node); 1241 break; 1242 } 1243 case IrOpcode::kObjectIsSmi: { 1244 ProcessInput(node, 0, UseInfo::AnyTagged()); 1245 SetOutput(node, NodeOutputInfo::Bool()); 1246 if (lower()) lowering->DoObjectIsSmi(node); 1247 break; 1248 } 1249 1250 //------------------------------------------------------------------ 1251 // Machine-level operators. 1252 //------------------------------------------------------------------ 1253 case IrOpcode::kLoad: { 1254 // TODO(jarin) Eventually, we should get rid of all machine stores 1255 // from the high-level phases, then this becomes UNREACHABLE. 1256 LoadRepresentation rep = LoadRepresentationOf(node->op()); 1257 ProcessInput(node, 0, UseInfo::AnyTagged()); // tagged pointer 1258 ProcessInput(node, 1, UseInfo::PointerInt()); // index 1259 ProcessRemainingInputs(node, 2); 1260 SetOutputFromMachineType(node, rep); 1261 break; 1262 } 1263 case IrOpcode::kStore: { 1264 // TODO(jarin) Eventually, we should get rid of all machine stores 1265 // from the high-level phases, then this becomes UNREACHABLE. 1266 StoreRepresentation rep = StoreRepresentationOf(node->op()); 1267 ProcessInput(node, 0, UseInfo::AnyTagged()); // tagged pointer 1268 ProcessInput(node, 1, UseInfo::PointerInt()); // index 1269 ProcessInput(node, 2, 1270 TruncatingUseInfoFromRepresentation(rep.representation())); 1271 ProcessRemainingInputs(node, 3); 1272 SetOutput(node, NodeOutputInfo::None()); 1273 break; 1274 } 1275 case IrOpcode::kWord32Shr: 1276 // We output unsigned int32 for shift right because JavaScript. 1277 return VisitBinop(node, UseInfo::TruncatingWord32(), 1278 NodeOutputInfo::Uint32()); 1279 case IrOpcode::kWord32And: 1280 case IrOpcode::kWord32Or: 1281 case IrOpcode::kWord32Xor: 1282 case IrOpcode::kWord32Shl: 1283 case IrOpcode::kWord32Sar: 1284 // We use signed int32 as the output type for these word32 operations, 1285 // though the machine bits are the same for either signed or unsigned, 1286 // because JavaScript considers the result from these operations signed. 1287 return VisitBinop(node, UseInfo::TruncatingWord32(), 1288 NodeOutputInfo::Int32()); 1289 case IrOpcode::kWord32Equal: 1290 return VisitBinop(node, UseInfo::TruncatingWord32(), 1291 NodeOutputInfo::Bool()); 1292 1293 case IrOpcode::kWord32Clz: 1294 return VisitUnop(node, UseInfo::TruncatingWord32(), 1295 NodeOutputInfo::Uint32()); 1296 1297 case IrOpcode::kInt32Add: 1298 case IrOpcode::kInt32Sub: 1299 case IrOpcode::kInt32Mul: 1300 case IrOpcode::kInt32MulHigh: 1301 case IrOpcode::kInt32Div: 1302 case IrOpcode::kInt32Mod: 1303 return VisitInt32Binop(node); 1304 case IrOpcode::kUint32Div: 1305 case IrOpcode::kUint32Mod: 1306 case IrOpcode::kUint32MulHigh: 1307 return VisitUint32Binop(node); 1308 case IrOpcode::kInt32LessThan: 1309 case IrOpcode::kInt32LessThanOrEqual: 1310 return VisitInt32Cmp(node); 1311 1312 case IrOpcode::kUint32LessThan: 1313 case IrOpcode::kUint32LessThanOrEqual: 1314 return VisitUint32Cmp(node); 1315 1316 case IrOpcode::kInt64Add: 1317 case IrOpcode::kInt64Sub: 1318 case IrOpcode::kInt64Mul: 1319 case IrOpcode::kInt64Div: 1320 case IrOpcode::kInt64Mod: 1321 return VisitInt64Binop(node); 1322 case IrOpcode::kInt64LessThan: 1323 case IrOpcode::kInt64LessThanOrEqual: 1324 return VisitInt64Cmp(node); 1325 1326 case IrOpcode::kUint64LessThan: 1327 return VisitUint64Cmp(node); 1328 1329 case IrOpcode::kUint64Div: 1330 case IrOpcode::kUint64Mod: 1331 return VisitUint64Binop(node); 1332 1333 case IrOpcode::kWord64And: 1334 case IrOpcode::kWord64Or: 1335 case IrOpcode::kWord64Xor: 1336 case IrOpcode::kWord64Shl: 1337 case IrOpcode::kWord64Shr: 1338 case IrOpcode::kWord64Sar: 1339 return VisitBinop(node, UseInfo::TruncatingWord64(), 1340 NodeOutputInfo::Int64()); 1341 case IrOpcode::kWord64Equal: 1342 return VisitBinop(node, UseInfo::TruncatingWord64(), 1343 NodeOutputInfo::Bool()); 1344 1345 case IrOpcode::kChangeInt32ToInt64: 1346 return VisitUnop( 1347 node, UseInfo::TruncatingWord32(), 1348 NodeOutputInfo(MachineRepresentation::kWord64, Type::Signed32())); 1349 case IrOpcode::kChangeUint32ToUint64: 1350 return VisitUnop( 1351 node, UseInfo::TruncatingWord32(), 1352 NodeOutputInfo(MachineRepresentation::kWord64, Type::Unsigned32())); 1353 case IrOpcode::kTruncateFloat64ToFloat32: 1354 return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Float32()); 1355 case IrOpcode::kTruncateFloat64ToInt32: 1356 return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Int32()); 1357 case IrOpcode::kTruncateInt64ToInt32: 1358 // TODO(titzer): Is kTypeInt32 correct here? 1359 return VisitUnop(node, UseInfo::Word64TruncatingToWord32(), 1360 NodeOutputInfo::Int32()); 1361 1362 case IrOpcode::kChangeFloat32ToFloat64: 1363 return VisitUnop(node, UseInfo::Float32(), NodeOutputInfo::Float64()); 1364 case IrOpcode::kChangeInt32ToFloat64: 1365 return VisitUnop( 1366 node, UseInfo::TruncatingWord32(), 1367 NodeOutputInfo(MachineRepresentation::kFloat64, Type::Signed32())); 1368 case IrOpcode::kChangeUint32ToFloat64: 1369 return VisitUnop(node, UseInfo::TruncatingWord32(), 1370 NodeOutputInfo(MachineRepresentation::kFloat64, 1371 Type::Unsigned32())); 1372 case IrOpcode::kChangeFloat64ToInt32: 1373 return VisitUnop(node, UseInfo::Float64TruncatingToWord32(), 1374 NodeOutputInfo::Int32()); 1375 case IrOpcode::kChangeFloat64ToUint32: 1376 return VisitUnop(node, UseInfo::Float64TruncatingToWord32(), 1377 NodeOutputInfo::Uint32()); 1378 1379 case IrOpcode::kFloat64Add: 1380 case IrOpcode::kFloat64Sub: 1381 case IrOpcode::kFloat64Mul: 1382 case IrOpcode::kFloat64Div: 1383 case IrOpcode::kFloat64Mod: 1384 case IrOpcode::kFloat64Min: 1385 return VisitFloat64Binop(node); 1386 case IrOpcode::kFloat64Abs: 1387 case IrOpcode::kFloat64Sqrt: 1388 case IrOpcode::kFloat64RoundDown: 1389 case IrOpcode::kFloat64RoundTruncate: 1390 case IrOpcode::kFloat64RoundTiesAway: 1391 return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Float64()); 1392 case IrOpcode::kFloat64Equal: 1393 case IrOpcode::kFloat64LessThan: 1394 case IrOpcode::kFloat64LessThanOrEqual: 1395 return VisitFloat64Cmp(node); 1396 case IrOpcode::kFloat64ExtractLowWord32: 1397 case IrOpcode::kFloat64ExtractHighWord32: 1398 return VisitUnop(node, UseInfo::Float64(), NodeOutputInfo::Int32()); 1399 case IrOpcode::kFloat64InsertLowWord32: 1400 case IrOpcode::kFloat64InsertHighWord32: 1401 return VisitBinop(node, UseInfo::Float64(), UseInfo::TruncatingWord32(), 1402 NodeOutputInfo::Float64()); 1403 case IrOpcode::kLoadStackPointer: 1404 case IrOpcode::kLoadFramePointer: 1405 return VisitLeaf(node, NodeOutputInfo::Pointer()); 1406 case IrOpcode::kStateValues: 1407 VisitStateValues(node); 1408 break; 1409 default: 1410 VisitInputs(node); 1411 // Assume the output is tagged. 1412 SetOutput(node, NodeOutputInfo::AnyTagged()); 1413 break; 1414 } 1415 } 1416 1417 void DeferReplacement(Node* node, Node* replacement) { 1418 TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(), 1419 node->op()->mnemonic(), replacement->id(), 1420 replacement->op()->mnemonic()); 1421 1422 if (replacement->id() < count_ && 1423 GetInfo(node)->output_type()->Is(GetInfo(replacement)->output_type())) { 1424 // Replace with a previously existing node eagerly only if the type is the 1425 // same. 1426 node->ReplaceUses(replacement); 1427 } else { 1428 // Otherwise, we are replacing a node with a representation change. 1429 // Such a substitution must be done after all lowering is done, because 1430 // changing the type could confuse the representation change 1431 // insertion for uses of the node. 1432 replacements_.push_back(node); 1433 replacements_.push_back(replacement); 1434 } 1435 node->NullAllInputs(); // Node is now dead. 1436 } 1437 1438 void PrintOutputInfo(NodeInfo* info) { 1439 if (FLAG_trace_representation) { 1440 OFStream os(stdout); 1441 os << info->representation() << " ("; 1442 info->output_type()->PrintTo(os, Type::SEMANTIC_DIM); 1443 os << ")"; 1444 } 1445 } 1446 1447 void PrintRepresentation(MachineRepresentation rep) { 1448 if (FLAG_trace_representation) { 1449 OFStream os(stdout); 1450 os << rep; 1451 } 1452 } 1453 1454 void PrintTruncation(Truncation truncation) { 1455 if (FLAG_trace_representation) { 1456 OFStream os(stdout); 1457 os << truncation.description(); 1458 } 1459 } 1460 1461 void PrintUseInfo(UseInfo info) { 1462 if (FLAG_trace_representation) { 1463 OFStream os(stdout); 1464 os << info.preferred() << ":" << info.truncation().description(); 1465 } 1466 } 1467 1468 private: 1469 JSGraph* jsgraph_; 1470 size_t const count_; // number of nodes in the graph 1471 ZoneVector<NodeInfo> info_; // node id -> usage information 1472 #ifdef DEBUG 1473 ZoneVector<InputUseInfos> node_input_use_infos_; // Debug information about 1474 // requirements on inputs. 1475 #endif // DEBUG 1476 NodeVector nodes_; // collected nodes 1477 NodeVector replacements_; // replacements to be done after lowering 1478 Phase phase_; // current phase of algorithm 1479 RepresentationChanger* changer_; // for inserting representation changes 1480 ZoneQueue<Node*> queue_; // queue for traversing the graph 1481 // TODO(danno): RepresentationSelector shouldn't know anything about the 1482 // source positions table, but must for now since there currently is no other 1483 // way to pass down source position information to nodes created during 1484 // lowering. Once this phase becomes a vanilla reducer, it should get source 1485 // position information via the SourcePositionWrapper like all other reducers. 1486 SourcePositionTable* source_positions_; 1487 TypeCache const& type_cache_; 1488 1489 NodeInfo* GetInfo(Node* node) { 1490 DCHECK(node->id() >= 0); 1491 DCHECK(node->id() < count_); 1492 return &info_[node->id()]; 1493 } 1494 }; 1495 1496 1497 SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, Zone* zone, 1498 SourcePositionTable* source_positions) 1499 : jsgraph_(jsgraph), 1500 zone_(zone), 1501 type_cache_(TypeCache::Get()), 1502 source_positions_(source_positions) {} 1503 1504 1505 void SimplifiedLowering::LowerAllNodes() { 1506 RepresentationChanger changer(jsgraph(), jsgraph()->isolate()); 1507 RepresentationSelector selector(jsgraph(), zone_, &changer, 1508 source_positions_); 1509 selector.Run(this); 1510 } 1511 1512 1513 void SimplifiedLowering::DoLoadBuffer(Node* node, 1514 MachineRepresentation output_rep, 1515 RepresentationChanger* changer) { 1516 DCHECK_EQ(IrOpcode::kLoadBuffer, node->opcode()); 1517 DCHECK_NE(MachineRepresentation::kNone, output_rep); 1518 MachineType const access_type = BufferAccessOf(node->op()).machine_type(); 1519 if (output_rep != access_type.representation()) { 1520 Node* const buffer = node->InputAt(0); 1521 Node* const offset = node->InputAt(1); 1522 Node* const length = node->InputAt(2); 1523 Node* const effect = node->InputAt(3); 1524 Node* const control = node->InputAt(4); 1525 Node* const index = 1526 machine()->Is64() 1527 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), offset) 1528 : offset; 1529 1530 Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length); 1531 Node* branch = 1532 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 1533 1534 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1535 Node* etrue = graph()->NewNode(machine()->Load(access_type), buffer, index, 1536 effect, if_true); 1537 Node* vtrue = changer->GetRepresentationFor( 1538 etrue, access_type.representation(), NodeProperties::GetType(node), 1539 output_rep, Truncation::None()); 1540 1541 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1542 Node* efalse = effect; 1543 Node* vfalse; 1544 if (output_rep == MachineRepresentation::kTagged) { 1545 vfalse = jsgraph()->UndefinedConstant(); 1546 } else if (output_rep == MachineRepresentation::kFloat64) { 1547 vfalse = 1548 jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN()); 1549 } else if (output_rep == MachineRepresentation::kFloat32) { 1550 vfalse = 1551 jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN()); 1552 } else { 1553 vfalse = jsgraph()->Int32Constant(0); 1554 } 1555 1556 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); 1557 Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge); 1558 1559 // Replace effect uses of {node} with the {ephi}. 1560 NodeProperties::ReplaceUses(node, node, ephi); 1561 1562 // Turn the {node} into a Phi. 1563 node->ReplaceInput(0, vtrue); 1564 node->ReplaceInput(1, vfalse); 1565 node->ReplaceInput(2, merge); 1566 node->TrimInputCount(3); 1567 NodeProperties::ChangeOp(node, common()->Phi(output_rep, 2)); 1568 } else { 1569 NodeProperties::ChangeOp(node, machine()->CheckedLoad(access_type)); 1570 } 1571 } 1572 1573 1574 void SimplifiedLowering::DoStoreBuffer(Node* node) { 1575 DCHECK_EQ(IrOpcode::kStoreBuffer, node->opcode()); 1576 MachineRepresentation const rep = 1577 BufferAccessOf(node->op()).machine_type().representation(); 1578 NodeProperties::ChangeOp(node, machine()->CheckedStore(rep)); 1579 } 1580 1581 1582 void SimplifiedLowering::DoObjectIsNumber(Node* node) { 1583 Node* input = NodeProperties::GetValueInput(node, 0); 1584 // TODO(bmeurer): Optimize somewhat based on input type. 1585 Node* check = 1586 graph()->NewNode(machine()->WordEqual(), 1587 graph()->NewNode(machine()->WordAnd(), input, 1588 jsgraph()->IntPtrConstant(kSmiTagMask)), 1589 jsgraph()->IntPtrConstant(kSmiTag)); 1590 Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start()); 1591 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 1592 Node* vtrue = jsgraph()->Int32Constant(1); 1593 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 1594 Node* vfalse = graph()->NewNode( 1595 machine()->WordEqual(), 1596 graph()->NewNode( 1597 machine()->Load(MachineType::AnyTagged()), input, 1598 jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), 1599 graph()->start(), if_false), 1600 jsgraph()->HeapConstant(isolate()->factory()->heap_number_map())); 1601 Node* control = graph()->NewNode(common()->Merge(2), if_true, if_false); 1602 node->ReplaceInput(0, vtrue); 1603 node->AppendInput(graph()->zone(), vfalse); 1604 node->AppendInput(graph()->zone(), control); 1605 NodeProperties::ChangeOp(node, common()->Phi(MachineRepresentation::kBit, 2)); 1606 } 1607 1608 1609 void SimplifiedLowering::DoObjectIsSmi(Node* node) { 1610 node->ReplaceInput(0, 1611 graph()->NewNode(machine()->WordAnd(), node->InputAt(0), 1612 jsgraph()->IntPtrConstant(kSmiTagMask))); 1613 node->AppendInput(graph()->zone(), jsgraph()->IntPtrConstant(kSmiTag)); 1614 NodeProperties::ChangeOp(node, machine()->WordEqual()); 1615 } 1616 1617 1618 Node* SimplifiedLowering::StringComparison(Node* node) { 1619 Operator::Properties properties = node->op()->properties(); 1620 Callable callable = CodeFactory::StringCompare(isolate()); 1621 CallDescriptor::Flags flags = CallDescriptor::kNoFlags; 1622 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 1623 isolate(), zone(), callable.descriptor(), 0, flags, properties); 1624 return graph()->NewNode( 1625 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), 1626 NodeProperties::GetValueInput(node, 0), 1627 NodeProperties::GetValueInput(node, 1), jsgraph()->NoContextConstant(), 1628 NodeProperties::GetEffectInput(node), 1629 NodeProperties::GetControlInput(node)); 1630 } 1631 1632 1633 Node* SimplifiedLowering::Int32Div(Node* const node) { 1634 Int32BinopMatcher m(node); 1635 Node* const zero = jsgraph()->Int32Constant(0); 1636 Node* const minus_one = jsgraph()->Int32Constant(-1); 1637 Node* const lhs = m.left().node(); 1638 Node* const rhs = m.right().node(); 1639 1640 if (m.right().Is(-1)) { 1641 return graph()->NewNode(machine()->Int32Sub(), zero, lhs); 1642 } else if (m.right().Is(0)) { 1643 return rhs; 1644 } else if (machine()->Int32DivIsSafe() || m.right().HasValue()) { 1645 return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start()); 1646 } 1647 1648 // General case for signed integer division. 1649 // 1650 // if 0 < rhs then 1651 // lhs / rhs 1652 // else 1653 // if rhs < -1 then 1654 // lhs / rhs 1655 // else if rhs == 0 then 1656 // 0 1657 // else 1658 // 0 - lhs 1659 // 1660 // Note: We do not use the Diamond helper class here, because it really hurts 1661 // readability with nested diamonds. 1662 const Operator* const merge_op = common()->Merge(2); 1663 const Operator* const phi_op = 1664 common()->Phi(MachineRepresentation::kWord32, 2); 1665 1666 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs); 1667 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, 1668 graph()->start()); 1669 1670 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1671 Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0); 1672 1673 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1674 Node* false0; 1675 { 1676 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one); 1677 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); 1678 1679 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1680 Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1); 1681 1682 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1683 Node* false1; 1684 { 1685 Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero); 1686 Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1); 1687 1688 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 1689 Node* true2 = zero; 1690 1691 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); 1692 Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs); 1693 1694 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2); 1695 false1 = graph()->NewNode(phi_op, true2, false2, if_false1); 1696 } 1697 1698 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1); 1699 false0 = graph()->NewNode(phi_op, true1, false1, if_false0); 1700 } 1701 1702 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0); 1703 return graph()->NewNode(phi_op, true0, false0, merge0); 1704 } 1705 1706 1707 Node* SimplifiedLowering::Int32Mod(Node* const node) { 1708 Int32BinopMatcher m(node); 1709 Node* const zero = jsgraph()->Int32Constant(0); 1710 Node* const minus_one = jsgraph()->Int32Constant(-1); 1711 Node* const lhs = m.left().node(); 1712 Node* const rhs = m.right().node(); 1713 1714 if (m.right().Is(-1) || m.right().Is(0)) { 1715 return zero; 1716 } else if (m.right().HasValue()) { 1717 return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start()); 1718 } 1719 1720 // General case for signed integer modulus, with optimization for (unknown) 1721 // power of 2 right hand side. 1722 // 1723 // if 0 < rhs then 1724 // msk = rhs - 1 1725 // if rhs & msk != 0 then 1726 // lhs % rhs 1727 // else 1728 // if lhs < 0 then 1729 // -(-lhs & msk) 1730 // else 1731 // lhs & msk 1732 // else 1733 // if rhs < -1 then 1734 // lhs % rhs 1735 // else 1736 // zero 1737 // 1738 // Note: We do not use the Diamond helper class here, because it really hurts 1739 // readability with nested diamonds. 1740 const Operator* const merge_op = common()->Merge(2); 1741 const Operator* const phi_op = 1742 common()->Phi(MachineRepresentation::kWord32, 2); 1743 1744 Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs); 1745 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, 1746 graph()->start()); 1747 1748 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1749 Node* true0; 1750 { 1751 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one); 1752 1753 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk); 1754 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0); 1755 1756 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1757 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1); 1758 1759 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1760 Node* false1; 1761 { 1762 Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero); 1763 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 1764 check2, if_false1); 1765 1766 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); 1767 Node* true2 = graph()->NewNode( 1768 machine()->Int32Sub(), zero, 1769 graph()->NewNode(machine()->Word32And(), 1770 graph()->NewNode(machine()->Int32Sub(), zero, lhs), 1771 msk)); 1772 1773 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); 1774 Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk); 1775 1776 if_false1 = graph()->NewNode(merge_op, if_true2, if_false2); 1777 false1 = graph()->NewNode(phi_op, true2, false2, if_false1); 1778 } 1779 1780 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1); 1781 true0 = graph()->NewNode(phi_op, true1, false1, if_true0); 1782 } 1783 1784 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1785 Node* false0; 1786 { 1787 Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one); 1788 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 1789 check1, if_false0); 1790 1791 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1792 Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1); 1793 1794 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1795 Node* false1 = zero; 1796 1797 if_false0 = graph()->NewNode(merge_op, if_true1, if_false1); 1798 false0 = graph()->NewNode(phi_op, true1, false1, if_false0); 1799 } 1800 1801 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0); 1802 return graph()->NewNode(phi_op, true0, false0, merge0); 1803 } 1804 1805 1806 Node* SimplifiedLowering::Uint32Div(Node* const node) { 1807 Uint32BinopMatcher m(node); 1808 Node* const zero = jsgraph()->Uint32Constant(0); 1809 Node* const lhs = m.left().node(); 1810 Node* const rhs = m.right().node(); 1811 1812 if (m.right().Is(0)) { 1813 return zero; 1814 } else if (machine()->Uint32DivIsSafe() || m.right().HasValue()) { 1815 return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start()); 1816 } 1817 1818 Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero); 1819 Diamond d(graph(), common(), check, BranchHint::kFalse); 1820 Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false); 1821 return d.Phi(MachineRepresentation::kWord32, zero, div); 1822 } 1823 1824 1825 Node* SimplifiedLowering::Uint32Mod(Node* const node) { 1826 Uint32BinopMatcher m(node); 1827 Node* const minus_one = jsgraph()->Int32Constant(-1); 1828 Node* const zero = jsgraph()->Uint32Constant(0); 1829 Node* const lhs = m.left().node(); 1830 Node* const rhs = m.right().node(); 1831 1832 if (m.right().Is(0)) { 1833 return zero; 1834 } else if (m.right().HasValue()) { 1835 return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start()); 1836 } 1837 1838 // General case for unsigned integer modulus, with optimization for (unknown) 1839 // power of 2 right hand side. 1840 // 1841 // if rhs then 1842 // msk = rhs - 1 1843 // if rhs & msk != 0 then 1844 // lhs % rhs 1845 // else 1846 // lhs & msk 1847 // else 1848 // zero 1849 // 1850 // Note: We do not use the Diamond helper class here, because it really hurts 1851 // readability with nested diamonds. 1852 const Operator* const merge_op = common()->Merge(2); 1853 const Operator* const phi_op = 1854 common()->Phi(MachineRepresentation::kWord32, 2); 1855 1856 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), rhs, 1857 graph()->start()); 1858 1859 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 1860 Node* true0; 1861 { 1862 Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one); 1863 1864 Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk); 1865 Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0); 1866 1867 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 1868 Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1); 1869 1870 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 1871 Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk); 1872 1873 if_true0 = graph()->NewNode(merge_op, if_true1, if_false1); 1874 true0 = graph()->NewNode(phi_op, true1, false1, if_true0); 1875 } 1876 1877 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 1878 Node* false0 = zero; 1879 1880 Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0); 1881 return graph()->NewNode(phi_op, true0, false0, merge0); 1882 } 1883 1884 1885 void SimplifiedLowering::DoShift(Node* node, Operator const* op, 1886 Type* rhs_type) { 1887 Node* const rhs = NodeProperties::GetValueInput(node, 1); 1888 if (!rhs_type->Is(type_cache_.kZeroToThirtyOne)) { 1889 node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs, 1890 jsgraph()->Int32Constant(0x1f))); 1891 } 1892 NodeProperties::ChangeOp(node, op); 1893 } 1894 1895 1896 namespace { 1897 1898 void ReplaceEffectUses(Node* node, Node* replacement) { 1899 // Requires distinguishing between value and effect edges. 1900 DCHECK(replacement->op()->EffectOutputCount() > 0); 1901 for (Edge edge : node->use_edges()) { 1902 if (NodeProperties::IsEffectEdge(edge)) { 1903 edge.UpdateTo(replacement); 1904 } else { 1905 DCHECK(NodeProperties::IsValueEdge(edge)); 1906 } 1907 } 1908 } 1909 1910 } // namespace 1911 1912 1913 void SimplifiedLowering::DoStringEqual(Node* node) { 1914 Node* comparison = StringComparison(node); 1915 ReplaceEffectUses(node, comparison); 1916 node->ReplaceInput(0, comparison); 1917 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); 1918 node->TrimInputCount(2); 1919 NodeProperties::ChangeOp(node, machine()->WordEqual()); 1920 } 1921 1922 1923 void SimplifiedLowering::DoStringLessThan(Node* node) { 1924 Node* comparison = StringComparison(node); 1925 ReplaceEffectUses(node, comparison); 1926 node->ReplaceInput(0, comparison); 1927 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); 1928 node->TrimInputCount(2); 1929 NodeProperties::ChangeOp(node, machine()->IntLessThan()); 1930 } 1931 1932 1933 void SimplifiedLowering::DoStringLessThanOrEqual(Node* node) { 1934 Node* comparison = StringComparison(node); 1935 ReplaceEffectUses(node, comparison); 1936 node->ReplaceInput(0, comparison); 1937 node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); 1938 node->TrimInputCount(2); 1939 NodeProperties::ChangeOp(node, machine()->IntLessThanOrEqual()); 1940 } 1941 1942 } // namespace compiler 1943 } // namespace internal 1944 } // namespace v8 1945