| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/bits.h" | 5 #include "src/base/bits.h" |
| 6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
| 7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 cont); | 534 cont); |
| 535 } | 535 } |
| 536 } | 536 } |
| 537 | 537 |
| 538 | 538 |
| 539 void VisitWordCompare(InstructionSelector* selector, Node* node, | 539 void VisitWordCompare(InstructionSelector* selector, Node* node, |
| 540 FlagsContinuation* cont) { | 540 FlagsContinuation* cont) { |
| 541 VisitWordCompare(selector, node, kMipsCmp, cont, false); | 541 VisitWordCompare(selector, node, kMipsCmp, cont, false); |
| 542 } | 542 } |
| 543 | 543 |
| 544 | |
| 545 void VisitWordTest(InstructionSelector* selector, Node* node, | |
| 546 FlagsContinuation* cont) { | |
| 547 MipsOperandGenerator g(selector); | |
| 548 // kMipsTst is a pseudo-instruction to do logical 'and' and leave the result | |
| 549 // in a dedicated tmp register. | |
| 550 VisitCompare(selector, kMipsTst, g.UseRegister(node), g.UseRegister(node), | |
| 551 cont); | |
| 552 } | |
| 553 | |
| 554 } // namespace | 544 } // namespace |
| 555 | 545 |
| 556 | 546 |
| 547 // Shared routine for word comparisons against zero. |
| 548 void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
| 549 Node* value, FlagsContinuation* cont) { |
| 550 while (selector->CanCover(user, value)) { |
| 551 switch (value->opcode()) { |
| 552 case IrOpcode::kWord32Equal: { |
| 553 // Combine with comparisons against 0 by simply inverting the |
| 554 // continuation. |
| 555 Int32BinopMatcher m(value); |
| 556 if (m.right().Is(0)) { |
| 557 user = value; |
| 558 value = m.left().node(); |
| 559 cont->Negate(); |
| 560 continue; |
| 561 } |
| 562 cont->OverwriteAndNegateIfEqual(kEqual); |
| 563 return VisitWordCompare(selector, value, cont); |
| 564 } |
| 565 case IrOpcode::kInt32LessThan: |
| 566 cont->OverwriteAndNegateIfEqual(kSignedLessThan); |
| 567 return VisitWordCompare(selector, value, cont); |
| 568 case IrOpcode::kInt32LessThanOrEqual: |
| 569 cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 570 return VisitWordCompare(selector, value, cont); |
| 571 case IrOpcode::kUint32LessThan: |
| 572 cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 573 return VisitWordCompare(selector, value, cont); |
| 574 case IrOpcode::kUint32LessThanOrEqual: |
| 575 cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
| 576 return VisitWordCompare(selector, value, cont); |
| 577 case IrOpcode::kFloat64Equal: |
| 578 cont->OverwriteAndNegateIfEqual(kUnorderedEqual); |
| 579 return VisitFloat64Compare(selector, value, cont); |
| 580 case IrOpcode::kFloat64LessThan: |
| 581 cont->OverwriteAndNegateIfEqual(kUnorderedLessThan); |
| 582 return VisitFloat64Compare(selector, value, cont); |
| 583 case IrOpcode::kFloat64LessThanOrEqual: |
| 584 cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
| 585 return VisitFloat64Compare(selector, value, cont); |
| 586 case IrOpcode::kProjection: |
| 587 // Check if this is the overflow output projection of an |
| 588 // <Operation>WithOverflow node. |
| 589 if (OpParameter<size_t>(value) == 1u) { |
| 590 // We cannot combine the <Operation>WithOverflow with this branch |
| 591 // unless the 0th projection (the use of the actual value of the |
| 592 // <Operation> is either NULL, which means there's no use of the |
| 593 // actual value, or was already defined, which means it is scheduled |
| 594 // *AFTER* this branch). |
| 595 Node* const node = value->InputAt(0); |
| 596 Node* const result = node->FindProjection(0); |
| 597 if (!result || selector->IsDefined(result)) { |
| 598 switch (node->opcode()) { |
| 599 case IrOpcode::kInt32AddWithOverflow: |
| 600 cont->OverwriteAndNegateIfEqual(kOverflow); |
| 601 return VisitBinop(selector, node, kMipsAddOvf, cont); |
| 602 case IrOpcode::kInt32SubWithOverflow: |
| 603 cont->OverwriteAndNegateIfEqual(kOverflow); |
| 604 return VisitBinop(selector, node, kMipsSubOvf, cont); |
| 605 default: |
| 606 break; |
| 607 } |
| 608 } |
| 609 } |
| 610 break; |
| 611 case IrOpcode::kWord32And: |
| 612 return VisitWordCompare(selector, value, kMipsTst, cont, true); |
| 613 default: |
| 614 break; |
| 615 } |
| 616 break; |
| 617 } |
| 618 |
| 619 // Continuation could not be combined with a compare, emit compare against 0. |
| 620 MipsOperandGenerator g(selector); |
| 621 InstructionCode const opcode = cont->Encode(kMipsCmp); |
| 622 InstructionOperand* const value_operand = g.UseRegister(value); |
| 623 if (cont->IsBranch()) { |
| 624 selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0), |
| 625 g.Label(cont->true_block()), |
| 626 g.Label(cont->false_block()))->MarkAsControl(); |
| 627 } else { |
| 628 selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand, |
| 629 g.TempImmediate(0)); |
| 630 } |
| 631 } |
| 632 |
| 633 |
| 557 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, | 634 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 558 BasicBlock* fbranch) { | 635 BasicBlock* fbranch) { |
| 559 MipsOperandGenerator g(this); | |
| 560 Node* user = branch; | |
| 561 Node* value = branch->InputAt(0); | |
| 562 | |
| 563 FlagsContinuation cont(kNotEqual, tbranch, fbranch); | 636 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 564 | |
| 565 // If we can fall through to the true block, invert the branch. | 637 // If we can fall through to the true block, invert the branch. |
| 566 if (IsNextInAssemblyOrder(tbranch)) { | 638 if (IsNextInAssemblyOrder(tbranch)) { |
| 567 cont.Negate(); | 639 cont.Negate(); |
| 568 cont.SwapBlocks(); | 640 cont.SwapBlocks(); |
| 569 } | 641 } |
| 570 | 642 VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); |
| 571 // Try to combine with comparisons against 0 by simply inverting the branch. | |
| 572 while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) { | |
| 573 Int32BinopMatcher m(value); | |
| 574 if (m.right().Is(0)) { | |
| 575 user = value; | |
| 576 value = m.left().node(); | |
| 577 cont.Negate(); | |
| 578 } else { | |
| 579 break; | |
| 580 } | |
| 581 } | |
| 582 | |
| 583 // Try to combine the branch with a comparison. | |
| 584 if (CanCover(user, value)) { | |
| 585 switch (value->opcode()) { | |
| 586 case IrOpcode::kWord32And: | |
| 587 // TODO(plind): understand the significance of 'IR and' special case. | |
| 588 return VisitWordCompare(this, value, kMipsTst, &cont, true); | |
| 589 default: | |
| 590 break; | |
| 591 } | |
| 592 } | |
| 593 | |
| 594 // Branch could not be combined with a compare, emit compare against 0. | |
| 595 return VisitWordTest(this, value, &cont); | |
| 596 } | 643 } |
| 597 | 644 |
| 598 | 645 |
| 599 void InstructionSelector::VisitWord32Equal(Node* const node) { | 646 void InstructionSelector::VisitWord32Equal(Node* const node) { |
| 600 Node* const user = node; | |
| 601 FlagsContinuation cont(kEqual, node); | 647 FlagsContinuation cont(kEqual, node); |
| 602 Int32BinopMatcher m(user); | 648 Int32BinopMatcher m(node); |
| 603 if (m.right().Is(0)) { | 649 if (m.right().Is(0)) { |
| 604 Node* const value = m.left().node(); | 650 return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); |
| 605 return VisitWordTest(this, value, &cont); | |
| 606 } | 651 } |
| 607 | |
| 608 VisitWordCompare(this, node, &cont); | 652 VisitWordCompare(this, node, &cont); |
| 609 } | 653 } |
| 610 | 654 |
| 611 | 655 |
| 612 void InstructionSelector::VisitInt32LessThan(Node* node) { | 656 void InstructionSelector::VisitInt32LessThan(Node* node) { |
| 613 FlagsContinuation cont(kSignedLessThan, node); | 657 FlagsContinuation cont(kSignedLessThan, node); |
| 614 VisitWordCompare(this, node, &cont); | 658 VisitWordCompare(this, node, &cont); |
| 615 } | 659 } |
| 616 | 660 |
| 617 | 661 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 InstructionSelector::SupportedMachineOperatorFlags() { | 720 InstructionSelector::SupportedMachineOperatorFlags() { |
| 677 return MachineOperatorBuilder::kInt32DivIsSafe | | 721 return MachineOperatorBuilder::kInt32DivIsSafe | |
| 678 MachineOperatorBuilder::kInt32ModIsSafe | | 722 MachineOperatorBuilder::kInt32ModIsSafe | |
| 679 MachineOperatorBuilder::kUint32DivIsSafe | | 723 MachineOperatorBuilder::kUint32DivIsSafe | |
| 680 MachineOperatorBuilder::kUint32ModIsSafe; | 724 MachineOperatorBuilder::kUint32ModIsSafe; |
| 681 } | 725 } |
| 682 | 726 |
| 683 } // namespace compiler | 727 } // namespace compiler |
| 684 } // namespace internal | 728 } // namespace internal |
| 685 } // namespace v8 | 729 } // namespace v8 |
| OLD | NEW |