| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 #ifndef VM_ASSEMBLER_ARM64_H_ | 5 #ifndef VM_ASSEMBLER_ARM64_H_ |
| 6 #define VM_ASSEMBLER_ARM64_H_ | 6 #define VM_ASSEMBLER_ARM64_H_ |
| 7 | 7 |
| 8 #ifndef VM_ASSEMBLER_H_ | 8 #ifndef VM_ASSEMBLER_H_ |
| 9 #error Do not include assembler_arm64.h directly; use assembler.h instead. | 9 #error Do not include assembler_arm64.h directly; use assembler.h instead. |
| 10 #endif | 10 #endif |
| (...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 } | 668 } |
| 669 void madd(Register rd, Register rn, Register rm, Register ra) { | 669 void madd(Register rd, Register rn, Register rm, Register ra) { |
| 670 EmitMiscDP3Source(MADD, rd, rn, rm, ra, kDoubleWord); | 670 EmitMiscDP3Source(MADD, rd, rn, rm, ra, kDoubleWord); |
| 671 } | 671 } |
| 672 void msub(Register rd, Register rn, Register rm, Register ra) { | 672 void msub(Register rd, Register rn, Register rm, Register ra) { |
| 673 EmitMiscDP3Source(MSUB, rd, rn, rm, ra, kDoubleWord); | 673 EmitMiscDP3Source(MSUB, rd, rn, rm, ra, kDoubleWord); |
| 674 } | 674 } |
| 675 void smulh(Register rd, Register rn, Register rm) { | 675 void smulh(Register rd, Register rn, Register rm) { |
| 676 EmitMiscDP3Source(SMULH, rd, rn, rm, R0, kDoubleWord); | 676 EmitMiscDP3Source(SMULH, rd, rn, rm, R0, kDoubleWord); |
| 677 } | 677 } |
| 678 void umaddl(Register rd, Register rn, Register rm, Register ra) { |
| 679 EmitMiscDP3Source(UMADDL, rd, rn, rm, ra, kDoubleWord); |
| 680 } |
| 678 | 681 |
| 679 // Move wide immediate. | 682 // Move wide immediate. |
| 680 void movk(Register rd, const Immediate& imm, int hw_idx) { | 683 void movk(Register rd, const Immediate& imm, int hw_idx) { |
| 681 ASSERT(rd != CSP); | 684 ASSERT(rd != CSP); |
| 682 const Register crd = ConcreteRegister(rd); | 685 const Register crd = ConcreteRegister(rd); |
| 683 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); | 686 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); |
| 684 } | 687 } |
| 685 void movn(Register rd, const Immediate& imm, int hw_idx) { | 688 void movn(Register rd, const Immediate& imm, int hw_idx) { |
| 686 ASSERT(rd != CSP); | 689 ASSERT(rd != CSP); |
| 687 const Register crd = ConcreteRegister(rd); | 690 const Register crd = ConcreteRegister(rd); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 775 // UXTX 0 on a 64-bit register (rm) is a nop, but forces R31 to be | 778 // UXTX 0 on a 64-bit register (rm) is a nop, but forces R31 to be |
| 776 // interpreted as CSP. | 779 // interpreted as CSP. |
| 777 cmp(CSP, Operand(rm, UXTX, 0)); | 780 cmp(CSP, Operand(rm, UXTX, 0)); |
| 778 } else { | 781 } else { |
| 779 cmp(rn, Operand(rm)); | 782 cmp(rn, Operand(rm)); |
| 780 } | 783 } |
| 781 } | 784 } |
| 782 | 785 |
| 783 // Conditional branch. | 786 // Conditional branch. |
| 784 void b(Label* label, Condition cond = AL) { | 787 void b(Label* label, Condition cond = AL) { |
| 785 EmitBranch(BCOND, cond, label); | 788 EmitConditionalBranch(BCOND, cond, label); |
| 786 } | 789 } |
| 787 | 790 |
| 788 void b(int32_t offset) { | 791 void b(int32_t offset) { |
| 789 EmitUnconditionalBranchOp(B, offset); | 792 EmitUnconditionalBranchOp(B, offset); |
| 790 } | 793 } |
| 791 void bl(int32_t offset) { | 794 void bl(int32_t offset) { |
| 792 EmitUnconditionalBranchOp(BL, offset); | 795 EmitUnconditionalBranchOp(BL, offset); |
| 793 } | 796 } |
| 794 | 797 |
| 795 // TODO(zra): cbz, cbnz. | 798 void cbz(Label* label, Register rt, OperandSize sz = kDoubleWord) { |
| 799 EmitCompareAndBranch(CBZ, rt, label, sz); |
| 800 } |
| 801 |
| 802 void cbnz(Label* label, Register rt, OperandSize sz = kDoubleWord) { |
| 803 EmitCompareAndBranch(CBNZ, rt, label, sz); |
| 804 } |
| 796 | 805 |
| 797 // Branch, link, return. | 806 // Branch, link, return. |
| 798 void br(Register rn) { | 807 void br(Register rn) { |
| 799 EmitUnconditionalBranchRegOp(BR, rn); | 808 EmitUnconditionalBranchRegOp(BR, rn); |
| 800 } | 809 } |
| 801 void blr(Register rn) { | 810 void blr(Register rn) { |
| 802 EmitUnconditionalBranchRegOp(BLR, rn); | 811 EmitUnconditionalBranchRegOp(BLR, rn); |
| 803 } | 812 } |
| 804 void ret(Register rn = R30) { | 813 void ret(Register rn = R30) { |
| 805 EmitUnconditionalBranchRegOp(RET, rn); | 814 EmitUnconditionalBranchRegOp(RET, rn); |
| (...skipping 767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1573 const int32_t imm32 = static_cast<int32_t>(imm); | 1582 const int32_t imm32 = static_cast<int32_t>(imm); |
| 1574 const int32_t off = (((imm32 >> 2) << kImm19Shift) & kImm19Mask); | 1583 const int32_t off = (((imm32 >> 2) << kImm19Shift) & kImm19Mask); |
| 1575 return (instr & ~kImm19Mask) | off; | 1584 return (instr & ~kImm19Mask) | off; |
| 1576 } | 1585 } |
| 1577 | 1586 |
| 1578 int64_t DecodeImm19BranchOffset(int32_t instr) { | 1587 int64_t DecodeImm19BranchOffset(int32_t instr) { |
| 1579 const int32_t off = (((instr & kImm19Mask) >> kImm19Shift) << 13) >> 11; | 1588 const int32_t off = (((instr & kImm19Mask) >> kImm19Shift) << 13) >> 11; |
| 1580 return static_cast<int64_t>(off); | 1589 return static_cast<int64_t>(off); |
| 1581 } | 1590 } |
| 1582 | 1591 |
| 1592 bool IsConditionalBranch(int32_t instr) { |
| 1593 return (instr & ConditionalBranchMask) == |
| 1594 (ConditionalBranchFixed & ConditionalBranchMask); |
| 1595 } |
| 1596 |
| 1597 bool IsCompareAndBranch(int32_t instr) { |
| 1598 return (instr & CompareAndBranchMask) == |
| 1599 (CompareAndBranchFixed & CompareAndBranchMask); |
| 1600 } |
| 1601 |
| 1583 Condition DecodeImm19BranchCondition(int32_t instr) { | 1602 Condition DecodeImm19BranchCondition(int32_t instr) { |
| 1584 return static_cast<Condition>((instr & kCondMask) >> kCondShift); | 1603 if (IsConditionalBranch(instr)) { |
| 1604 return static_cast<Condition>((instr & kCondMask) >> kCondShift); |
| 1605 } |
| 1606 ASSERT(IsCompareAndBranch(instr)); |
| 1607 return (instr & B24) ? EQ : NE; // cbz : cbnz |
| 1585 } | 1608 } |
| 1586 | 1609 |
| 1587 int32_t EncodeImm19BranchCondition(Condition cond, int32_t instr) { | 1610 int32_t EncodeImm19BranchCondition(Condition cond, int32_t instr) { |
| 1588 const int32_t c_imm = static_cast<int32_t>(cond); | 1611 if (IsConditionalBranch(instr)) { |
| 1589 return (instr & ~kCondMask) | (c_imm << kCondShift); | 1612 const int32_t c_imm = static_cast<int32_t>(cond); |
| 1613 return (instr & ~kCondMask) | (c_imm << kCondShift); |
| 1614 } |
| 1615 ASSERT(IsCompareAndBranch(instr)); |
| 1616 return (instr & ~B24) | (cond == EQ ? B24 : 0); // cbz : cbnz |
| 1590 } | 1617 } |
| 1591 | 1618 |
| 1592 int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr) { | 1619 int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr) { |
| 1593 const int32_t imm32 = static_cast<int32_t>(imm); | 1620 const int32_t imm32 = static_cast<int32_t>(imm); |
| 1594 const int32_t off = (((imm32 >> 2) << kImm26Shift) & kImm26Mask); | 1621 const int32_t off = (((imm32 >> 2) << kImm26Shift) & kImm26Mask); |
| 1595 return (instr & ~kImm26Mask) | off; | 1622 return (instr & ~kImm26Mask) | off; |
| 1596 } | 1623 } |
| 1597 | 1624 |
| 1598 int64_t DecodeImm26BranchOffset(int32_t instr) { | 1625 int64_t DecodeImm26BranchOffset(int32_t instr) { |
| 1599 const int32_t off = (((instr & kImm26Mask) >> kImm26Shift) << 6) >> 4; | 1626 const int32_t off = (((instr & kImm26Mask) >> kImm26Shift) << 6) >> 4; |
| 1600 return static_cast<int64_t>(off); | 1627 return static_cast<int64_t>(off); |
| 1601 } | 1628 } |
| 1602 | 1629 |
| 1603 void EmitCompareAndBranch(CompareAndBranchOp op, Register rt, int64_t imm, | 1630 void EmitCompareAndBranchOp(CompareAndBranchOp op, Register rt, int64_t imm, |
| 1604 OperandSize sz) { | 1631 OperandSize sz) { |
| 1605 ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord)); | 1632 ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord)); |
| 1606 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); | 1633 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); |
| 1607 ASSERT((rt != CSP) && (rt != R31)); | 1634 ASSERT((rt != CSP) && (rt != R31)); |
| 1608 const Register crt = ConcreteRegister(rt); | 1635 const Register crt = ConcreteRegister(rt); |
| 1609 const int32_t size = (sz == kDoubleWord) ? B31 : 0; | 1636 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 1610 const int32_t encoded_offset = EncodeImm19BranchOffset(imm, 0); | 1637 const int32_t encoded_offset = EncodeImm19BranchOffset(imm, 0); |
| 1611 const int32_t encoding = | 1638 const int32_t encoding = |
| 1612 op | size | | 1639 op | size | |
| 1613 (static_cast<int32_t>(crt) << kRtShift) | | 1640 (static_cast<int32_t>(crt) << kRtShift) | |
| 1614 encoded_offset; | 1641 encoded_offset; |
| 1615 Emit(encoding); | 1642 Emit(encoding); |
| 1616 } | 1643 } |
| 1617 | 1644 |
| 1618 void EmitConditionalBranch(ConditionalBranchOp op, Condition cond, | 1645 void EmitConditionalBranchOp(ConditionalBranchOp op, Condition cond, |
| 1619 int64_t imm) { | 1646 int64_t imm) { |
| 1620 const int32_t off = EncodeImm19BranchOffset(imm, 0); | 1647 const int32_t off = EncodeImm19BranchOffset(imm, 0); |
| 1621 const int32_t encoding = | 1648 const int32_t encoding = |
| 1622 op | | 1649 op | |
| 1623 (static_cast<int32_t>(cond) << kCondShift) | | 1650 (static_cast<int32_t>(cond) << kCondShift) | |
| 1624 off; | 1651 off; |
| 1625 Emit(encoding); | 1652 Emit(encoding); |
| 1626 } | 1653 } |
| 1627 | 1654 |
| 1628 bool CanEncodeImm19BranchOffset(int64_t offset) { | 1655 bool CanEncodeImm19BranchOffset(int64_t offset) { |
| 1629 ASSERT(Utils::IsAligned(offset, 4)); | 1656 ASSERT(Utils::IsAligned(offset, 4)); |
| 1630 return Utils::IsInt(21, offset); | 1657 return Utils::IsInt(21, offset); |
| 1631 } | 1658 } |
| 1632 | 1659 |
| 1633 void EmitBranch(ConditionalBranchOp op, Condition cond, Label* label) { | 1660 void EmitConditionalBranch(ConditionalBranchOp op, Condition cond, |
| 1661 Label* label) { |
| 1634 if (label->IsBound()) { | 1662 if (label->IsBound()) { |
| 1635 const int64_t dest = label->Position() - buffer_.Size(); | 1663 const int64_t dest = label->Position() - buffer_.Size(); |
| 1636 if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) { | 1664 if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) { |
| 1637 if (cond == AL) { | 1665 if (cond == AL) { |
| 1638 // If the condition is AL, we must always branch to dest. There is | 1666 // If the condition is AL, we must always branch to dest. There is |
| 1639 // no need for a guard branch. | 1667 // no need for a guard branch. |
| 1640 b(dest); | 1668 b(dest); |
| 1641 } else { | 1669 } else { |
| 1642 EmitConditionalBranch( | 1670 EmitConditionalBranchOp( |
| 1643 op, InvertCondition(cond), 2 * Instr::kInstrSize); | 1671 op, InvertCondition(cond), 2 * Instr::kInstrSize); |
| 1644 b(dest); | 1672 b(dest); |
| 1645 } | 1673 } |
| 1646 } else { | 1674 } else { |
| 1647 EmitConditionalBranch(op, cond, dest); | 1675 EmitConditionalBranchOp(op, cond, dest); |
| 1648 } | 1676 } |
| 1649 } else { | 1677 } else { |
| 1650 const int64_t position = buffer_.Size(); | 1678 const int64_t position = buffer_.Size(); |
| 1651 if (use_far_branches()) { | 1679 if (use_far_branches()) { |
| 1652 // When cond is AL, this guard branch will be rewritten as a nop when | 1680 // When cond is AL, this guard branch will be rewritten as a nop when |
| 1653 // the label is bound. We don't write it as a nop initially because it | 1681 // the label is bound. We don't write it as a nop initially because it |
| 1654 // makes the decoding code in Bind simpler. | 1682 // makes the decoding code in Bind simpler. |
| 1655 EmitConditionalBranch(op, InvertCondition(cond), 2 * Instr::kInstrSize); | 1683 EmitConditionalBranchOp( |
| 1684 op, InvertCondition(cond), 2 * Instr::kInstrSize); |
| 1656 b(label->position_); | 1685 b(label->position_); |
| 1657 } else { | 1686 } else { |
| 1658 EmitConditionalBranch(op, cond, label->position_); | 1687 EmitConditionalBranchOp(op, cond, label->position_); |
| 1688 } |
| 1689 label->LinkTo(position); |
| 1690 } |
| 1691 } |
| 1692 |
| 1693 void EmitCompareAndBranch(CompareAndBranchOp op, Register rt, |
| 1694 Label* label, OperandSize sz) { |
| 1695 if (label->IsBound()) { |
| 1696 const int64_t dest = label->Position() - buffer_.Size(); |
| 1697 if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) { |
| 1698 EmitCompareAndBranchOp( |
| 1699 op == CBZ ? CBNZ : CBZ, rt, 2 * Instr::kInstrSize, sz); |
| 1700 b(dest); |
| 1701 } else { |
| 1702 EmitCompareAndBranchOp(op, rt, dest, sz); |
| 1703 } |
| 1704 } else { |
| 1705 const int64_t position = buffer_.Size(); |
| 1706 if (use_far_branches()) { |
| 1707 EmitCompareAndBranchOp( |
| 1708 op == CBZ ? CBNZ : CBZ, rt, 2 * Instr::kInstrSize, sz); |
| 1709 b(label->position_); |
| 1710 } else { |
| 1711 EmitCompareAndBranchOp(op, rt, label->position_, sz); |
| 1659 } | 1712 } |
| 1660 label->LinkTo(position); | 1713 label->LinkTo(position); |
| 1661 } | 1714 } |
| 1662 } | 1715 } |
| 1663 | 1716 |
| 1664 bool CanEncodeImm26BranchOffset(int64_t offset) { | 1717 bool CanEncodeImm26BranchOffset(int64_t offset) { |
| 1665 ASSERT(Utils::IsAligned(offset, 4)); | 1718 ASSERT(Utils::IsAligned(offset, 4)); |
| 1666 return Utils::IsInt(26, offset); | 1719 return Utils::IsInt(26, offset); |
| 1667 } | 1720 } |
| 1668 | 1721 |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1898 Register value, | 1951 Register value, |
| 1899 Label* no_update); | 1952 Label* no_update); |
| 1900 | 1953 |
| 1901 DISALLOW_ALLOCATION(); | 1954 DISALLOW_ALLOCATION(); |
| 1902 DISALLOW_COPY_AND_ASSIGN(Assembler); | 1955 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 1903 }; | 1956 }; |
| 1904 | 1957 |
| 1905 } // namespace dart | 1958 } // namespace dart |
| 1906 | 1959 |
| 1907 #endif // VM_ASSEMBLER_ARM64_H_ | 1960 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |