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 |