| 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 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 encoding_ = other.encoding_; | 98 encoding_ = other.encoding_; |
| 99 type_ = other.type_; | 99 type_ = other.type_; |
| 100 base_ = other.base_; | 100 base_ = other.base_; |
| 101 return *this; | 101 return *this; |
| 102 } | 102 } |
| 103 | 103 |
| 104 enum AddressType { | 104 enum AddressType { |
| 105 Offset, | 105 Offset, |
| 106 PreIndex, | 106 PreIndex, |
| 107 PostIndex, | 107 PostIndex, |
| 108 PairOffset, |
| 109 PairPreIndex, |
| 110 PairPostIndex, |
| 108 Reg, | 111 Reg, |
| 109 PCOffset, | 112 PCOffset, |
| 110 Unknown, | 113 Unknown, |
| 111 }; | 114 }; |
| 112 | 115 |
| 113 // Offset is in bytes. For the unsigned imm12 case, we unscale based on the | 116 // Offset is in bytes. For the unsigned imm12 case, we unscale based on the |
| 114 // operand size, and assert that offset is aligned accordingly. | 117 // operand size, and assert that offset is aligned accordingly. |
| 115 // For the smaller signed imm9 case, the offset is the number of bytes, but | 118 // For the smaller signed imm9 case, the offset is the number of bytes, but |
| 116 // is unscaled. | 119 // is unscaled. |
| 117 Address(Register rn, int32_t offset = 0, AddressType at = Offset, | 120 Address(Register rn, int32_t offset = 0, AddressType at = Offset, |
| 118 OperandSize sz = kDoubleWord) { | 121 OperandSize sz = kDoubleWord) { |
| 119 ASSERT((rn != R31) && (rn != ZR)); | 122 ASSERT((rn != R31) && (rn != ZR)); |
| 120 ASSERT(CanHoldOffset(offset, at, sz)); | 123 ASSERT(CanHoldOffset(offset, at, sz)); |
| 121 const Register crn = ConcreteRegister(rn); | 124 const Register crn = ConcreteRegister(rn); |
| 122 const int32_t scale = Log2OperandSizeBytes(sz); | 125 const int32_t scale = Log2OperandSizeBytes(sz); |
| 123 if ((at == Offset) && | 126 if ((at == Offset) && |
| 124 Utils::IsUint(12 + scale, offset) && | 127 Utils::IsUint(12 + scale, offset) && |
| 125 (offset == ((offset >> scale) << scale))) { | 128 (offset == ((offset >> scale) << scale))) { |
| 126 encoding_ = | 129 encoding_ = |
| 127 B24 | | 130 B24 | |
| 128 ((offset >> scale) << kImm12Shift) | | 131 ((offset >> scale) << kImm12Shift) | |
| 129 (static_cast<int32_t>(crn) << kRnShift); | 132 (static_cast<int32_t>(crn) << kRnShift); |
| 130 } else if ((at == Offset) && | 133 } else if ((at == Offset) && |
| 131 Utils::IsInt(9, offset)) { | 134 Utils::IsInt(9, offset)) { |
| 132 encoding_ = | 135 encoding_ = |
| 133 ((offset & 0x1ff) << kImm9Shift) | | 136 ((offset & 0x1ff) << kImm9Shift) | |
| 134 (static_cast<int32_t>(crn) << kRnShift); | 137 (static_cast<int32_t>(crn) << kRnShift); |
| 135 } else { | 138 } else if ((at == PreIndex) || (at == PostIndex)) { |
| 136 ASSERT(Utils::IsInt(9, offset)); | 139 ASSERT(Utils::IsInt(9, offset)); |
| 137 ASSERT((at == PreIndex) || (at == PostIndex)); | |
| 138 int32_t idx = (at == PostIndex) ? B10 : (B11 | B10); | 140 int32_t idx = (at == PostIndex) ? B10 : (B11 | B10); |
| 139 encoding_ = | 141 encoding_ = |
| 140 idx | | 142 idx | |
| 141 ((offset & 0x1ff) << kImm9Shift) | | 143 ((offset & 0x1ff) << kImm9Shift) | |
| 142 (static_cast<int32_t>(crn) << kRnShift); | 144 (static_cast<int32_t>(crn) << kRnShift); |
| 145 } else { |
| 146 ASSERT((at == PairOffset) || (at == PairPreIndex) || |
| 147 (at == PairPostIndex)); |
| 148 ASSERT(Utils::IsInt(7 + scale, offset) && |
| 149 (offset == ((offset >> scale) << scale))); |
| 150 int32_t idx = 0; |
| 151 switch (at) { |
| 152 case PairPostIndex: idx = B23; break; |
| 153 case PairPreIndex: idx = B24 | B23; break; |
| 154 case PairOffset: idx = B24; break; |
| 155 default: UNREACHABLE(); break; |
| 156 } |
| 157 encoding_ = |
| 158 idx | |
| 159 (((offset >> scale) << kImm7Shift) & kImm7Mask) | |
| 160 (static_cast<int32_t>(crn) << kRnShift); |
| 143 } | 161 } |
| 144 type_ = at; | 162 type_ = at; |
| 145 base_ = crn; | 163 base_ = crn; |
| 146 } | 164 } |
| 147 | 165 |
| 148 // This addressing mode does not exist. | 166 // This addressing mode does not exist. |
| 149 Address(Register rn, Register offset, AddressType at, | 167 Address(Register rn, Register offset, AddressType at, |
| 150 OperandSize sz = kDoubleWord); | 168 OperandSize sz = kDoubleWord); |
| 151 | 169 |
| 152 static bool CanHoldOffset(int32_t offset, AddressType at = Offset, | 170 static bool CanHoldOffset(int32_t offset, AddressType at = Offset, |
| 153 OperandSize sz = kDoubleWord) { | 171 OperandSize sz = kDoubleWord) { |
| 154 if (at == Offset) { | 172 if (at == Offset) { |
| 155 // Offset fits in 12 bit unsigned and has right alignment for sz, | 173 // Offset fits in 12 bit unsigned and has right alignment for sz, |
| 156 // or fits in 9 bit signed offset with no alignment restriction. | 174 // or fits in 9 bit signed offset with no alignment restriction. |
| 157 const int32_t scale = Log2OperandSizeBytes(sz); | 175 const int32_t scale = Log2OperandSizeBytes(sz); |
| 158 return (Utils::IsUint(12 + scale, offset) && | 176 return (Utils::IsUint(12 + scale, offset) && |
| 159 (offset == ((offset >> scale) << scale))) || | 177 (offset == ((offset >> scale) << scale))) || |
| 160 (Utils::IsInt(9, offset)); | 178 (Utils::IsInt(9, offset)); |
| 161 } else if (at == PCOffset) { | 179 } else if (at == PCOffset) { |
| 162 return Utils::IsInt(21, offset) && | 180 return Utils::IsInt(21, offset) && |
| 163 (offset == ((offset >> 2) << 2)); | 181 (offset == ((offset >> 2) << 2)); |
| 182 } else if ((at == PreIndex) || (at == PostIndex)) { |
| 183 return Utils::IsInt(9, offset); |
| 164 } else { | 184 } else { |
| 165 ASSERT((at == PreIndex) || (at == PostIndex)); | 185 ASSERT((at == PairOffset) || (at == PairPreIndex) || |
| 166 return Utils::IsInt(9, offset); | 186 (at == PairPostIndex)); |
| 187 const int32_t scale = Log2OperandSizeBytes(sz); |
| 188 return (Utils::IsInt(7 + scale, offset) && |
| 189 (offset == ((offset >> scale) << scale))); |
| 167 } | 190 } |
| 168 } | 191 } |
| 169 | 192 |
| 170 // PC-relative load address. | 193 // PC-relative load address. |
| 171 static Address PC(int32_t pc_off) { | 194 static Address PC(int32_t pc_off) { |
| 172 ASSERT(CanHoldOffset(pc_off, PCOffset)); | 195 ASSERT(CanHoldOffset(pc_off, PCOffset)); |
| 173 Address addr; | 196 Address addr; |
| 174 addr.encoding_ = (((pc_off >> 2) << kImm19Shift) & kImm19Mask); | 197 addr.encoding_ = (((pc_off >> 2) << kImm19Shift) & kImm19Mask); |
| 175 addr.base_ = kNoRegister; | 198 addr.base_ = kNoRegister; |
| 176 addr.type_ = PCOffset; | 199 addr.type_ = PCOffset; |
| 177 return addr; | 200 return addr; |
| 178 } | 201 } |
| 179 | 202 |
| 203 static Address Pair(Register rn, |
| 204 int32_t offset = 0, |
| 205 AddressType at = PairOffset, |
| 206 OperandSize sz = kDoubleWord) { |
| 207 return Address(rn, offset, at, sz); |
| 208 } |
| 209 |
| 180 // This addressing mode does not exist. | 210 // This addressing mode does not exist. |
| 181 static Address PC(Register r); | 211 static Address PC(Register r); |
| 182 | 212 |
| 183 enum Scaling { | 213 enum Scaling { |
| 184 Unscaled, | 214 Unscaled, |
| 185 Scaled, | 215 Scaled, |
| 186 }; | 216 }; |
| 187 | 217 |
| 188 // Base register rn with offset rm. rm is sign-extended according to ext. | 218 // Base register rn with offset rm. rm is sign-extended according to ext. |
| 189 // If ext is UXTX, rm may be optionally scaled by the | 219 // If ext is UXTX, rm may be optionally scaled by the |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); | 653 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); |
| 624 } | 654 } |
| 625 void movz(Register rd, const Immediate& imm, int hw_idx) { | 655 void movz(Register rd, const Immediate& imm, int hw_idx) { |
| 626 ASSERT(rd != CSP); | 656 ASSERT(rd != CSP); |
| 627 const Register crd = ConcreteRegister(rd); | 657 const Register crd = ConcreteRegister(rd); |
| 628 EmitMoveWideOp(MOVZ, crd, imm, hw_idx, kDoubleWord); | 658 EmitMoveWideOp(MOVZ, crd, imm, hw_idx, kDoubleWord); |
| 629 } | 659 } |
| 630 | 660 |
| 631 // Loads and Stores. | 661 // Loads and Stores. |
| 632 void ldr(Register rt, Address a, OperandSize sz = kDoubleWord) { | 662 void ldr(Register rt, Address a, OperandSize sz = kDoubleWord) { |
| 663 ASSERT((a.type() != Address::PairOffset) && |
| 664 (a.type() != Address::PairPostIndex) && |
| 665 (a.type() != Address::PairPreIndex)); |
| 633 if (a.type() == Address::PCOffset) { | 666 if (a.type() == Address::PCOffset) { |
| 634 ASSERT(sz == kDoubleWord); | 667 ASSERT(sz == kDoubleWord); |
| 635 EmitLoadRegLiteral(LDRpc, rt, a, sz); | 668 EmitLoadRegLiteral(LDRpc, rt, a, sz); |
| 636 } else { | 669 } else { |
| 637 // If we are doing pre-/post-indexing, and the base and result registers | 670 // If we are doing pre-/post-indexing, and the base and result registers |
| 638 // are the same, then the result of the load will be clobbered by the | 671 // are the same, then the result of the load will be clobbered by the |
| 639 // writeback, which is unlikely to be useful. | 672 // writeback, which is unlikely to be useful. |
| 640 ASSERT(((a.type() != Address::PreIndex) && | 673 ASSERT(((a.type() != Address::PreIndex) && |
| 641 (a.type() != Address::PostIndex)) || | 674 (a.type() != Address::PostIndex)) || |
| 642 (rt != a.base())); | 675 (rt != a.base())); |
| 643 if (IsSignedOperand(sz)) { | 676 if (IsSignedOperand(sz)) { |
| 644 EmitLoadStoreReg(LDRS, rt, a, sz); | 677 EmitLoadStoreReg(LDRS, rt, a, sz); |
| 645 } else { | 678 } else { |
| 646 EmitLoadStoreReg(LDR, rt, a, sz); | 679 EmitLoadStoreReg(LDR, rt, a, sz); |
| 647 } | 680 } |
| 648 } | 681 } |
| 649 } | 682 } |
| 650 void str(Register rt, Address a, OperandSize sz = kDoubleWord) { | 683 void str(Register rt, Address a, OperandSize sz = kDoubleWord) { |
| 684 ASSERT((a.type() != Address::PairOffset) && |
| 685 (a.type() != Address::PairPostIndex) && |
| 686 (a.type() != Address::PairPreIndex)); |
| 651 EmitLoadStoreReg(STR, rt, a, sz); | 687 EmitLoadStoreReg(STR, rt, a, sz); |
| 652 } | 688 } |
| 653 | 689 |
| 690 void ldp(Register rt, Register rt2, Address a, OperandSize sz = kDoubleWord) { |
| 691 ASSERT((a.type() == Address::PairOffset) || |
| 692 (a.type() == Address::PairPostIndex) || |
| 693 (a.type() == Address::PairPreIndex)); |
| 694 EmitLoadStoreRegPair(LDP, rt, rt2, a, sz); |
| 695 } |
| 696 void stp(Register rt, Register rt2, Address a, OperandSize sz = kDoubleWord) { |
| 697 ASSERT((a.type() == Address::PairOffset) || |
| 698 (a.type() == Address::PairPostIndex) || |
| 699 (a.type() == Address::PairPreIndex)); |
| 700 EmitLoadStoreRegPair(STP, rt, rt2, a, sz); |
| 701 } |
| 702 |
| 654 // Conditional select. | 703 // Conditional select. |
| 655 void csel(Register rd, Register rn, Register rm, Condition cond) { | 704 void csel(Register rd, Register rn, Register rm, Condition cond) { |
| 656 EmitConditionalSelect(CSEL, rd, rn, rm, cond, kDoubleWord); | 705 EmitConditionalSelect(CSEL, rd, rn, rm, cond, kDoubleWord); |
| 657 } | 706 } |
| 658 void csinc(Register rd, Register rn, Register rm, Condition cond) { | 707 void csinc(Register rd, Register rn, Register rm, Condition cond) { |
| 659 EmitConditionalSelect(CSINC, rd, rn, rm, cond, kDoubleWord); | 708 EmitConditionalSelect(CSINC, rd, rn, rm, cond, kDoubleWord); |
| 660 } | 709 } |
| 661 void cinc(Register rd, Register rn, Condition cond) { | 710 void cinc(Register rd, Register rn, Condition cond) { |
| 662 csinc(rd, rn, rn, InvertCondition(cond)); | 711 csinc(rd, rn, rn, InvertCondition(cond)); |
| 663 } | 712 } |
| (...skipping 930 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1594 ASSERT((rt != CSP) && (rt != R31)); | 1643 ASSERT((rt != CSP) && (rt != R31)); |
| 1595 const Register crt = ConcreteRegister(rt); | 1644 const Register crt = ConcreteRegister(rt); |
| 1596 const int32_t size = (sz == kDoubleWord) ? B30 : 0; | 1645 const int32_t size = (sz == kDoubleWord) ? B30 : 0; |
| 1597 const int32_t encoding = | 1646 const int32_t encoding = |
| 1598 op | size | | 1647 op | size | |
| 1599 (static_cast<int32_t>(crt) << kRtShift) | | 1648 (static_cast<int32_t>(crt) << kRtShift) | |
| 1600 a.encoding(); | 1649 a.encoding(); |
| 1601 Emit(encoding); | 1650 Emit(encoding); |
| 1602 } | 1651 } |
| 1603 | 1652 |
| 1653 void EmitLoadStoreRegPair(LoadStoreRegPairOp op, |
| 1654 Register rt, Register rt2, Address a, |
| 1655 OperandSize sz) { |
| 1656 ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord)); |
| 1657 ASSERT((rt != CSP) && (rt != R31)); |
| 1658 ASSERT((rt2 != CSP) && (rt2 != R31)); |
| 1659 const Register crt = ConcreteRegister(rt); |
| 1660 const Register crt2 = ConcreteRegister(rt2); |
| 1661 int32_t opc; |
| 1662 switch (sz) { |
| 1663 case kDoubleWord: opc = B31; break; |
| 1664 case kWord: opc = B30; break; |
| 1665 case kUnsignedWord: opc = 0; break; |
| 1666 default: UNREACHABLE(); break; |
| 1667 } |
| 1668 const int32_t encoding = |
| 1669 opc | op | |
| 1670 (static_cast<int32_t>(crt) << kRtShift) | |
| 1671 (static_cast<int32_t>(crt2) << kRt2Shift) | |
| 1672 a.encoding(); |
| 1673 Emit(encoding); |
| 1674 } |
| 1675 |
| 1604 void EmitPCRelOp(PCRelOp op, Register rd, const Immediate& imm) { | 1676 void EmitPCRelOp(PCRelOp op, Register rd, const Immediate& imm) { |
| 1605 ASSERT(Utils::IsInt(21, imm.value())); | 1677 ASSERT(Utils::IsInt(21, imm.value())); |
| 1606 ASSERT((rd != R31) && (rd != CSP)); | 1678 ASSERT((rd != R31) && (rd != CSP)); |
| 1607 const Register crd = ConcreteRegister(rd); | 1679 const Register crd = ConcreteRegister(rd); |
| 1608 const int32_t loimm = (imm.value() & 0x3) << 29; | 1680 const int32_t loimm = (imm.value() & 0x3) << 29; |
| 1609 const int32_t hiimm = ((imm.value() >> 2) << kImm19Shift) & kImm19Mask; | 1681 const int32_t hiimm = ((imm.value() >> 2) << kImm19Shift) & kImm19Mask; |
| 1610 const int32_t encoding = | 1682 const int32_t encoding = |
| 1611 op | loimm | hiimm | | 1683 op | loimm | hiimm | |
| 1612 (static_cast<int32_t>(crd) << kRdShift); | 1684 (static_cast<int32_t>(crd) << kRdShift); |
| 1613 Emit(encoding); | 1685 Emit(encoding); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1748 Register value, | 1820 Register value, |
| 1749 Label* no_update); | 1821 Label* no_update); |
| 1750 | 1822 |
| 1751 DISALLOW_ALLOCATION(); | 1823 DISALLOW_ALLOCATION(); |
| 1752 DISALLOW_COPY_AND_ASSIGN(Assembler); | 1824 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 1753 }; | 1825 }; |
| 1754 | 1826 |
| 1755 } // namespace dart | 1827 } // namespace dart |
| 1756 | 1828 |
| 1757 #endif // VM_ASSEMBLER_ARM64_H_ | 1829 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |