OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
10 #include "vm/flow_graph_allocator.h" | 10 #include "vm/flow_graph_allocator.h" |
(...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 set_previous(NULL); | 753 set_previous(NULL); |
754 set_next(NULL); | 754 set_next(NULL); |
755 } | 755 } |
756 | 756 |
757 | 757 |
758 BranchInstr::BranchInstr(ComparisonInstr* comparison, bool is_checked) | 758 BranchInstr::BranchInstr(ComparisonInstr* comparison, bool is_checked) |
759 : comparison_(comparison), | 759 : comparison_(comparison), |
760 is_checked_(is_checked), | 760 is_checked_(is_checked), |
761 constrained_type_(NULL), | 761 constrained_type_(NULL), |
762 constant_target_(NULL) { | 762 constant_target_(NULL) { |
| 763 ASSERT(comparison->env() == NULL); |
763 for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) { | 764 for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) { |
764 comparison->InputAt(i)->set_instruction(this); | 765 comparison->InputAt(i)->set_instruction(this); |
765 } | 766 } |
766 } | 767 } |
767 | 768 |
768 | 769 |
769 void BranchInstr::RawSetInputAt(intptr_t i, Value* value) { | 770 void BranchInstr::RawSetInputAt(intptr_t i, Value* value) { |
770 comparison()->RawSetInputAt(i, value); | 771 comparison()->RawSetInputAt(i, value); |
771 } | 772 } |
772 | 773 |
773 | 774 |
774 // A misleadingly named function for use in template functions that replace | 775 // A misleadingly named function for use in template functions that replace |
775 // both definitions with definitions and branch comparisons with | 776 // both definitions with definitions and branch comparisons with |
776 // comparisons. In the branch case, leave the branch intact and replace its | 777 // comparisons. In the branch case, leave the branch intact and replace its |
777 // comparison with a new comparison not currently in the graph. | 778 // comparison with a new comparison not currently in the graph. |
778 void BranchInstr::ReplaceWith(ComparisonInstr* other, | 779 void BranchInstr::ReplaceWith(ComparisonInstr* other, |
779 ForwardInstructionIterator* ignored) { | 780 ForwardInstructionIterator* ignored) { |
780 SetComparison(other); | 781 SetComparison(other); |
781 } | 782 } |
782 | 783 |
783 | 784 |
784 void BranchInstr::SetComparison(ComparisonInstr* comp) { | 785 void BranchInstr::SetComparison(ComparisonInstr* new_comparison) { |
785 for (intptr_t i = comp->InputCount() - 1; i >= 0; --i) { | 786 for (intptr_t i = new_comparison->InputCount() - 1; i >= 0; --i) { |
786 Value* input = comp->InputAt(i); | 787 Value* input = new_comparison->InputAt(i); |
787 input->definition()->AddInputUse(input); | 788 input->definition()->AddInputUse(input); |
788 input->set_instruction(this); | 789 input->set_instruction(this); |
789 } | 790 } |
790 // There should be no need to copy or unuse an environment. | 791 // There should be no need to copy or unuse an environment. |
791 ASSERT(comparison()->env() == NULL); | 792 ASSERT(comparison()->env() == NULL); |
| 793 ASSERT(new_comparison->env() == NULL); |
792 // Remove the current comparison's input uses. | 794 // Remove the current comparison's input uses. |
793 comparison()->UnuseAllInputs(); | 795 comparison()->UnuseAllInputs(); |
794 ASSERT(!comp->HasUses()); | 796 ASSERT(!new_comparison->HasUses()); |
795 comparison_ = comp; | 797 comparison_ = new_comparison; |
796 } | 798 } |
797 | 799 |
798 | 800 |
799 // ==== Postorder graph traversal. | 801 // ==== Postorder graph traversal. |
800 static bool IsMarked(BlockEntryInstr* block, | 802 static bool IsMarked(BlockEntryInstr* block, |
801 GrowableArray<BlockEntryInstr*>* preorder) { | 803 GrowableArray<BlockEntryInstr*>* preorder) { |
802 // Detect that a block has been visited as part of the current | 804 // Detect that a block has been visited as part of the current |
803 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block | 805 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block |
804 // will be 'marked' by (1) having a preorder number in the range of the | 806 // will be 'marked' by (1) having a preorder number in the range of the |
805 // preorder array and (2) being in the preorder array at that index. | 807 // preorder array and (2) being in the preorder array at that index. |
(...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1610 other_defn->IsComparison() && | 1612 other_defn->IsComparison() && |
1611 (other->Type()->ToCid() == kBoolCid) && | 1613 (other->Type()->ToCid() == kBoolCid) && |
1612 other_defn->HasOnlyUse(other)) { | 1614 other_defn->HasOnlyUse(other)) { |
1613 *negated = true; | 1615 *negated = true; |
1614 return other_defn; | 1616 return other_defn; |
1615 } | 1617 } |
1616 return compare; | 1618 return compare; |
1617 } | 1619 } |
1618 | 1620 |
1619 | 1621 |
| 1622 // Recognize the pattern (a & b) == 0 where left is a bitwise and operation |
| 1623 // and right is a constant 0. |
| 1624 static bool RecognizeTestPattern(Value* left, Value* right) { |
| 1625 if (!right->BindsToConstant()) { |
| 1626 return false; |
| 1627 } |
| 1628 |
| 1629 const Object& value = right->BoundConstant(); |
| 1630 if (!value.IsSmi() || (Smi::Cast(value).Value() != 0)) { |
| 1631 return false; |
| 1632 } |
| 1633 |
| 1634 Definition* left_defn = left->definition(); |
| 1635 return left_defn->IsBinarySmiOp() && |
| 1636 (left_defn->AsBinarySmiOp()->op_kind() == Token::kBIT_AND) && |
| 1637 left_defn->HasOnlyUse(left); |
| 1638 } |
| 1639 |
| 1640 |
1620 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { | 1641 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { |
1621 // Only handle strict-compares. | 1642 // Only handle strict-compares. |
1622 if (comparison()->IsStrictCompare()) { | 1643 if (comparison()->IsStrictCompare()) { |
1623 bool negated = false; | 1644 bool negated = false; |
1624 Definition* replacement = | 1645 Definition* replacement = |
1625 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated); | 1646 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated); |
1626 if (replacement == comparison()) { | 1647 if (replacement == comparison()) { |
1627 return this; | 1648 return this; |
1628 } | 1649 } |
1629 ComparisonInstr* comp = replacement->AsComparison(); | 1650 ComparisonInstr* comp = replacement->AsComparison(); |
(...skipping 27 matching lines...) Expand all Loading... |
1657 SetComparison(comp); | 1678 SetComparison(comp); |
1658 if (FLAG_trace_optimization) { | 1679 if (FLAG_trace_optimization) { |
1659 OS::Print("Merging comparison v%" Pd "\n", comp->ssa_temp_index()); | 1680 OS::Print("Merging comparison v%" Pd "\n", comp->ssa_temp_index()); |
1660 } | 1681 } |
1661 // Clear the comparison's temp index and ssa temp index since the | 1682 // Clear the comparison's temp index and ssa temp index since the |
1662 // value of the comparison is not used outside the branch anymore. | 1683 // value of the comparison is not used outside the branch anymore. |
1663 ASSERT(comp->input_use_list() == NULL); | 1684 ASSERT(comp->input_use_list() == NULL); |
1664 comp->ClearSSATempIndex(); | 1685 comp->ClearSSATempIndex(); |
1665 comp->ClearTempIndex(); | 1686 comp->ClearTempIndex(); |
1666 } | 1687 } |
| 1688 } else if (comparison()->IsEqualityCompare() && |
| 1689 comparison()->operation_cid() == kSmiCid) { |
| 1690 BinarySmiOpInstr* bit_and = NULL; |
| 1691 if (RecognizeTestPattern(comparison()->left(), comparison()->right())) { |
| 1692 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); |
| 1693 } else if (RecognizeTestPattern(comparison()->right(), |
| 1694 comparison()->left())) { |
| 1695 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); |
| 1696 } |
| 1697 if (bit_and != NULL) { |
| 1698 if (FLAG_trace_optimization) { |
| 1699 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); |
| 1700 } |
| 1701 TestSmiInstr* test = new TestSmiInstr(comparison()->token_pos(), |
| 1702 comparison()->kind(), |
| 1703 bit_and->left()->Copy(), |
| 1704 bit_and->right()->Copy()); |
| 1705 ASSERT(!CanDeoptimize()); |
| 1706 RemoveEnvironment(); |
| 1707 flow_graph->CopyDeoptTarget(this, bit_and); |
| 1708 SetComparison(test); |
| 1709 bit_and->RemoveFromGraph(); |
| 1710 } |
1667 } | 1711 } |
1668 return this; | 1712 return this; |
1669 } | 1713 } |
1670 | 1714 |
1671 | 1715 |
1672 Definition* StrictCompareInstr::Canonicalize(FlowGraph* flow_graph) { | 1716 Definition* StrictCompareInstr::Canonicalize(FlowGraph* flow_graph) { |
1673 bool negated = false; | 1717 bool negated = false; |
1674 Definition* replacement = CanonicalizeStrictCompare(this, &negated); | 1718 Definition* replacement = CanonicalizeStrictCompare(this, &negated); |
1675 if (negated && replacement->IsComparison()) { | 1719 if (negated && replacement->IsComparison()) { |
1676 ASSERT(replacement != this); | 1720 ASSERT(replacement != this); |
(...skipping 1200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2877 return kCosRuntimeEntry; | 2921 return kCosRuntimeEntry; |
2878 default: | 2922 default: |
2879 UNREACHABLE(); | 2923 UNREACHABLE(); |
2880 } | 2924 } |
2881 return kSinRuntimeEntry; | 2925 return kSinRuntimeEntry; |
2882 } | 2926 } |
2883 | 2927 |
2884 #undef __ | 2928 #undef __ |
2885 | 2929 |
2886 } // namespace dart | 2930 } // namespace dart |
OLD | NEW |