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/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/base/bits.h" | 6 #include "src/base/bits.h" |
7 #include "src/compiler/instruction-selector-impl.h" | 7 #include "src/compiler/instruction-selector-impl.h" |
8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 | 10 |
(...skipping 1574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1585 } else if (m.left().Is(0.0)) { | 1585 } else if (m.left().Is(0.0)) { |
1586 cont->Commute(); | 1586 cont->Commute(); |
1587 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()), | 1587 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.right().node()), |
1588 g.UseImmediate(m.left().node()), cont); | 1588 g.UseImmediate(m.left().node()), cont); |
1589 } else { | 1589 } else { |
1590 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()), | 1590 VisitCompare(selector, kArmVcmpF64, g.UseRegister(m.left().node()), |
1591 g.UseRegister(m.right().node()), cont); | 1591 g.UseRegister(m.right().node()), cont); |
1592 } | 1592 } |
1593 } | 1593 } |
1594 | 1594 |
| 1595 // Check whether we can convert: |
| 1596 // ((a <op> b) cmp 0), b.<cond> |
| 1597 // to: |
| 1598 // (a <ops> b), b.<cond'> |
| 1599 // where <ops> is the flag setting version of <op>. |
| 1600 // We only generate conditions <cond'> that are a combination of the N |
| 1601 // and Z flags. This avoids the need to make this function dependent on |
| 1602 // the flag-setting operation. |
| 1603 bool CanUseFlagSettingBinop(FlagsCondition cond) { |
| 1604 switch (cond) { |
| 1605 case kEqual: |
| 1606 case kNotEqual: |
| 1607 case kSignedLessThan: |
| 1608 case kSignedGreaterThanOrEqual: |
| 1609 case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0 |
| 1610 case kUnsignedGreaterThan: // x > 0 -> x != 0 |
| 1611 return true; |
| 1612 default: |
| 1613 return false; |
| 1614 } |
| 1615 } |
| 1616 |
| 1617 // Map <cond> to <cond'> so that the following transformation is possible: |
| 1618 // ((a <op> b) cmp 0), b.<cond> |
| 1619 // to: |
| 1620 // (a <ops> b), b.<cond'> |
| 1621 // where <ops> is the flag setting version of <op>. |
| 1622 FlagsCondition MapForFlagSettingBinop(FlagsCondition cond) { |
| 1623 DCHECK(CanUseFlagSettingBinop(cond)); |
| 1624 switch (cond) { |
| 1625 case kEqual: |
| 1626 case kNotEqual: |
| 1627 return cond; |
| 1628 case kSignedLessThan: |
| 1629 return kNegative; |
| 1630 case kSignedGreaterThanOrEqual: |
| 1631 return kPositiveOrZero; |
| 1632 case kUnsignedLessThanOrEqual: // x <= 0 -> x == 0 |
| 1633 return kEqual; |
| 1634 case kUnsignedGreaterThan: // x > 0 -> x != 0 |
| 1635 return kNotEqual; |
| 1636 default: |
| 1637 UNREACHABLE(); |
| 1638 return cond; |
| 1639 } |
| 1640 } |
| 1641 |
| 1642 // Check if we can perform the transformation: |
| 1643 // ((a <op> b) cmp 0), b.<cond> |
| 1644 // to: |
| 1645 // (a <ops> b), b.<cond'> |
| 1646 // where <ops> is the flag setting version of <op>, and if so, |
| 1647 // updates {node}, {opcode} and {cont} accordingly. |
| 1648 void MaybeReplaceCmpZeroWithFlagSettingBinop(InstructionSelector* selector, |
| 1649 Node** node, Node* binop, |
| 1650 InstructionCode* opcode, |
| 1651 FlagsCondition cond, |
| 1652 FlagsContinuation* cont) { |
| 1653 InstructionCode binop_opcode; |
| 1654 InstructionCode no_output_opcode; |
| 1655 switch (binop->opcode()) { |
| 1656 case IrOpcode::kInt32Add: |
| 1657 binop_opcode = kArmAdd; |
| 1658 no_output_opcode = kArmCmn; |
| 1659 break; |
| 1660 case IrOpcode::kWord32And: |
| 1661 binop_opcode = kArmAnd; |
| 1662 no_output_opcode = kArmTst; |
| 1663 break; |
| 1664 case IrOpcode::kWord32Or: |
| 1665 binop_opcode = kArmOrr; |
| 1666 no_output_opcode = kArmOrr; |
| 1667 break; |
| 1668 case IrOpcode::kWord32Xor: |
| 1669 binop_opcode = kArmEor; |
| 1670 no_output_opcode = kArmTeq; |
| 1671 break; |
| 1672 default: |
| 1673 UNREACHABLE(); |
| 1674 return; |
| 1675 } |
| 1676 if (selector->CanCover(*node, binop)) { |
| 1677 // The comparison is the only user of {node}. |
| 1678 cont->Overwrite(MapForFlagSettingBinop(cond)); |
| 1679 *opcode = no_output_opcode; |
| 1680 *node = binop; |
| 1681 } else if (selector->IsOnlyUserOfNodeInSameBlock(*node, binop)) { |
| 1682 // We can also handle the case where the {node} and the comparison are in |
| 1683 // the same basic block, and the comparison is the only user of {node} in |
| 1684 // this basic block ({node} has users in other basic blocks). |
| 1685 cont->Overwrite(MapForFlagSettingBinop(cond)); |
| 1686 *opcode = binop_opcode; |
| 1687 *node = binop; |
| 1688 } |
| 1689 } |
1595 | 1690 |
1596 // Shared routine for multiple word compare operations. | 1691 // Shared routine for multiple word compare operations. |
1597 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1692 void VisitWordCompare(InstructionSelector* selector, Node* node, |
1598 InstructionCode opcode, FlagsContinuation* cont) { | 1693 InstructionCode opcode, FlagsContinuation* cont) { |
1599 ArmOperandGenerator g(selector); | 1694 ArmOperandGenerator g(selector); |
1600 Int32BinopMatcher m(node); | 1695 Int32BinopMatcher m(node); |
1601 InstructionOperand inputs[5]; | 1696 InstructionOperand inputs[5]; |
1602 size_t input_count = 0; | 1697 size_t input_count = 0; |
1603 InstructionOperand outputs[1]; | 1698 InstructionOperand outputs[2]; |
1604 size_t output_count = 0; | 1699 size_t output_count = 0; |
| 1700 bool has_result = (opcode != kArmCmp) && (opcode != kArmCmn) && |
| 1701 (opcode != kArmTst) && (opcode != kArmTeq); |
1605 | 1702 |
1606 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), | 1703 if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(), |
1607 &input_count, &inputs[1])) { | 1704 &input_count, &inputs[1])) { |
1608 inputs[0] = g.UseRegister(m.left().node()); | 1705 inputs[0] = g.UseRegister(m.left().node()); |
1609 input_count++; | 1706 input_count++; |
1610 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), | 1707 } else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(), |
1611 &input_count, &inputs[1])) { | 1708 &input_count, &inputs[1])) { |
1612 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); | 1709 if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); |
1613 inputs[0] = g.UseRegister(m.right().node()); | 1710 inputs[0] = g.UseRegister(m.right().node()); |
1614 input_count++; | 1711 input_count++; |
1615 } else { | 1712 } else { |
1616 opcode |= AddressingModeField::encode(kMode_Operand2_R); | 1713 opcode |= AddressingModeField::encode(kMode_Operand2_R); |
1617 inputs[input_count++] = g.UseRegister(m.left().node()); | 1714 inputs[input_count++] = g.UseRegister(m.left().node()); |
1618 inputs[input_count++] = g.UseRegister(m.right().node()); | 1715 inputs[input_count++] = g.UseRegister(m.right().node()); |
1619 } | 1716 } |
1620 | 1717 |
| 1718 if (has_result) { |
| 1719 if (cont->IsDeoptimize()) { |
| 1720 // If we can deoptimize as a result of the binop, we need to make sure |
| 1721 // that the deopt inputs are not overwritten by the binop result. One way |
| 1722 // to achieve that is to declare the output register as same-as-first. |
| 1723 outputs[output_count++] = g.DefineSameAsFirst(node); |
| 1724 } else { |
| 1725 outputs[output_count++] = g.DefineAsRegister(node); |
| 1726 } |
| 1727 } |
| 1728 |
1621 if (cont->IsBranch()) { | 1729 if (cont->IsBranch()) { |
1622 inputs[input_count++] = g.Label(cont->true_block()); | 1730 inputs[input_count++] = g.Label(cont->true_block()); |
1623 inputs[input_count++] = g.Label(cont->false_block()); | 1731 inputs[input_count++] = g.Label(cont->false_block()); |
1624 } else if (cont->IsSet()) { | 1732 } else if (cont->IsSet()) { |
1625 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 1733 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
1626 } | 1734 } |
1627 | 1735 |
1628 DCHECK_NE(0u, input_count); | 1736 DCHECK_NE(0u, input_count); |
1629 DCHECK_GE(arraysize(inputs), input_count); | 1737 DCHECK_GE(arraysize(inputs), input_count); |
1630 DCHECK_GE(arraysize(outputs), output_count); | 1738 DCHECK_GE(arraysize(outputs), output_count); |
1631 | 1739 |
1632 opcode = cont->Encode(opcode); | 1740 opcode = cont->Encode(opcode); |
1633 if (cont->IsDeoptimize()) { | 1741 if (cont->IsDeoptimize()) { |
1634 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, | 1742 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, |
1635 cont->frame_state()); | 1743 cont->frame_state()); |
1636 } else { | 1744 } else { |
1637 selector->Emit(opcode, output_count, outputs, input_count, inputs); | 1745 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
1638 } | 1746 } |
1639 } | 1747 } |
1640 | 1748 |
1641 | 1749 |
1642 void VisitWordCompare(InstructionSelector* selector, Node* node, | 1750 void VisitWordCompare(InstructionSelector* selector, Node* node, |
1643 FlagsContinuation* cont) { | 1751 FlagsContinuation* cont) { |
1644 VisitWordCompare(selector, node, kArmCmp, cont); | 1752 InstructionCode opcode = kArmCmp; |
| 1753 Int32BinopMatcher m(node); |
| 1754 |
| 1755 FlagsCondition cond = cont->condition(); |
| 1756 if (m.right().Is(0) && (m.left().IsInt32Add() || m.left().IsWord32Or() || |
| 1757 m.left().IsWord32And() || m.left().IsWord32Xor())) { |
| 1758 // Emit flag setting instructions for comparisons against zero. |
| 1759 if (CanUseFlagSettingBinop(cond)) { |
| 1760 Node* binop = m.left().node(); |
| 1761 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode, |
| 1762 cond, cont); |
| 1763 } |
| 1764 } else if (m.left().Is(0) && |
| 1765 (m.right().IsInt32Add() || m.right().IsWord32Or() || |
| 1766 m.right().IsWord32And() || m.right().IsWord32Xor())) { |
| 1767 // Same as above, but we need to commute the condition before we |
| 1768 // continue with the rest of the checks. |
| 1769 cond = CommuteFlagsCondition(cond); |
| 1770 if (CanUseFlagSettingBinop(cond)) { |
| 1771 Node* binop = m.right().node(); |
| 1772 MaybeReplaceCmpZeroWithFlagSettingBinop(selector, &node, binop, &opcode, |
| 1773 cond, cont); |
| 1774 } |
| 1775 } |
| 1776 |
| 1777 VisitWordCompare(selector, node, opcode, cont); |
1645 } | 1778 } |
1646 | 1779 |
1647 | 1780 |
1648 // Shared routine for word comparisons against zero. | 1781 // Shared routine for word comparisons against zero. |
1649 void VisitWordCompareZero(InstructionSelector* selector, Node* user, | 1782 void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
1650 Node* value, FlagsContinuation* cont) { | 1783 Node* value, FlagsContinuation* cont) { |
1651 while (selector->CanCover(user, value)) { | 1784 while (selector->CanCover(user, value)) { |
1652 switch (value->opcode()) { | 1785 switch (value->opcode()) { |
1653 case IrOpcode::kWord32Equal: { | 1786 case IrOpcode::kWord32Equal: { |
1654 // Combine with comparisons against 0 by simply inverting the | 1787 // Combine with comparisons against 0 by simply inverting the |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2053 // static | 2186 // static |
2054 MachineOperatorBuilder::AlignmentRequirements | 2187 MachineOperatorBuilder::AlignmentRequirements |
2055 InstructionSelector::AlignmentRequirements() { | 2188 InstructionSelector::AlignmentRequirements() { |
2056 return MachineOperatorBuilder::AlignmentRequirements:: | 2189 return MachineOperatorBuilder::AlignmentRequirements:: |
2057 FullUnalignedAccessSupport(); | 2190 FullUnalignedAccessSupport(); |
2058 } | 2191 } |
2059 | 2192 |
2060 } // namespace compiler | 2193 } // namespace compiler |
2061 } // namespace internal | 2194 } // namespace internal |
2062 } // namespace v8 | 2195 } // namespace v8 |
OLD | NEW |