| 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 |
| 11 | 11 |
| 12 #include "platform/assert.h" | 12 #include "platform/assert.h" |
| 13 #include "platform/utils.h" | 13 #include "platform/utils.h" |
| 14 #include "vm/constants_arm64.h" | 14 #include "vm/constants_arm64.h" |
| 15 #include "vm/hash_map.h" | 15 #include "vm/hash_map.h" |
| 16 #include "vm/longjump.h" |
| 16 #include "vm/object.h" | 17 #include "vm/object.h" |
| 17 #include "vm/simulator.h" | 18 #include "vm/simulator.h" |
| 18 | 19 |
| 19 namespace dart { | 20 namespace dart { |
| 20 | 21 |
| 21 // Forward declarations. | 22 // Forward declarations. |
| 22 class RuntimeEntry; | 23 class RuntimeEntry; |
| 23 | 24 |
| 24 // TODO(zra): Label, Address, and FieldAddress are copied from ARM, | 25 // TODO(zra): Label, Address, and FieldAddress are copied from ARM, |
| 25 // they must be adapted to ARM64. | 26 // they must be adapted to ARM64. |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 } else { | 595 } else { |
| 595 cmp(rn, Operand(rm)); | 596 cmp(rn, Operand(rm)); |
| 596 } | 597 } |
| 597 } | 598 } |
| 598 | 599 |
| 599 // Conditional branch. | 600 // Conditional branch. |
| 600 void b(Label* label, Condition cond = AL) { | 601 void b(Label* label, Condition cond = AL) { |
| 601 EmitBranch(BCOND, cond, label); | 602 EmitBranch(BCOND, cond, label); |
| 602 } | 603 } |
| 603 | 604 |
| 604 // TODO(zra): branch and link with imm26 offset. | 605 void b(int32_t offset) { |
| 606 EmitUnconditionalBranchOp(B, offset); |
| 607 } |
| 608 void bl(int32_t offset) { |
| 609 EmitUnconditionalBranchOp(BL, offset); |
| 610 } |
| 611 |
| 605 // TODO(zra): cbz, cbnz. | 612 // TODO(zra): cbz, cbnz. |
| 606 | 613 |
| 607 // Branch, link, return. | 614 // Branch, link, return. |
| 608 void br(Register rn) { | 615 void br(Register rn) { |
| 609 EmitUnconditionalBranchRegOp(BR, rn); | 616 EmitUnconditionalBranchRegOp(BR, rn); |
| 610 } | 617 } |
| 611 void blr(Register rn) { | 618 void blr(Register rn) { |
| 612 EmitUnconditionalBranchRegOp(BLR, rn); | 619 EmitUnconditionalBranchRegOp(BLR, rn); |
| 613 } | 620 } |
| 614 void ret(Register rn = R30) { | 621 void ret(Register rn = R30) { |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 } | 801 } |
| 795 | 802 |
| 796 // Fixed length branch to label. | 803 // Fixed length branch to label. |
| 797 void BranchPatchable(const ExternalLabel* label) { | 804 void BranchPatchable(const ExternalLabel* label) { |
| 798 // TODO(zra): Use LoadExternalLabelFixed if possible. | 805 // TODO(zra): Use LoadExternalLabelFixed if possible. |
| 799 LoadImmediateFixed(TMP, label->address()); | 806 LoadImmediateFixed(TMP, label->address()); |
| 800 br(TMP); | 807 br(TMP); |
| 801 } | 808 } |
| 802 | 809 |
| 803 void BranchLink(const ExternalLabel* label, Register pp) { | 810 void BranchLink(const ExternalLabel* label, Register pp) { |
| 804 if (Isolate::Current() == Dart::vm_isolate()) { | 811 LoadExternalLabel(TMP, label, kNotPatchable, pp); |
| 805 LoadImmediate(TMP, label->address(), kNoPP); | 812 blr(TMP); |
| 806 blr(TMP); | |
| 807 } else { | |
| 808 LoadExternalLabel(TMP, label, kNotPatchable, pp); | |
| 809 blr(TMP); | |
| 810 } | |
| 811 } | 813 } |
| 812 | 814 |
| 813 // BranchLinkPatchable must be a fixed-length sequence so we can patch it | 815 // BranchLinkPatchable must be a fixed-length sequence so we can patch it |
| 814 // with the debugger. | 816 // with the debugger. |
| 815 void BranchLinkPatchable(const ExternalLabel* label) { | 817 void BranchLinkPatchable(const ExternalLabel* label) { |
| 816 LoadExternalLabelFixed(TMP, label, kPatchable, PP); | 818 LoadExternalLabelFixed(TMP, label, kPatchable, PP); |
| 817 blr(TMP); | 819 blr(TMP); |
| 818 } | 820 } |
| 819 | 821 |
| 820 // Macros accepting a pp Register argument may attempt to load values from | 822 // Macros accepting a pp Register argument may attempt to load values from |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 const int32_t s = set_flags ? B29 : 0; | 1121 const int32_t s = set_flags ? B29 : 0; |
| 1120 const int32_t encoding = | 1122 const int32_t encoding = |
| 1121 op | size | s | | 1123 op | size | s | |
| 1122 (static_cast<int32_t>(rd) << kRdShift) | | 1124 (static_cast<int32_t>(rd) << kRdShift) | |
| 1123 (static_cast<int32_t>(rn) << kRnShift) | | 1125 (static_cast<int32_t>(rn) << kRnShift) | |
| 1124 o.encoding(); | 1126 o.encoding(); |
| 1125 Emit(encoding); | 1127 Emit(encoding); |
| 1126 } | 1128 } |
| 1127 | 1129 |
| 1128 int32_t EncodeImm19BranchOffset(int64_t imm, int32_t instr) { | 1130 int32_t EncodeImm19BranchOffset(int64_t imm, int32_t instr) { |
| 1131 if (!CanEncodeImm19BranchOffset(imm)) { |
| 1132 ASSERT(!use_far_branches()); |
| 1133 Isolate::Current()->long_jump_base()->Jump( |
| 1134 1, Object::branch_offset_error()); |
| 1135 } |
| 1129 const int32_t imm32 = static_cast<int32_t>(imm); | 1136 const int32_t imm32 = static_cast<int32_t>(imm); |
| 1130 const int32_t off = (((imm32 >> 2) << kImm19Shift) & kImm19Mask); | 1137 const int32_t off = (((imm32 >> 2) << kImm19Shift) & kImm19Mask); |
| 1131 return (instr & ~kImm19Mask) | off; | 1138 return (instr & ~kImm19Mask) | off; |
| 1132 } | 1139 } |
| 1133 | 1140 |
| 1134 int64_t DecodeImm19BranchOffset(int32_t instr) { | 1141 int64_t DecodeImm19BranchOffset(int32_t instr) { |
| 1135 const int32_t off = (((instr & kImm19Mask) >> kImm19Shift) << 13) >> 11; | 1142 const int32_t off = (((instr & kImm19Mask) >> kImm19Shift) << 13) >> 11; |
| 1136 return static_cast<int64_t>(off); | 1143 return static_cast<int64_t>(off); |
| 1137 } | 1144 } |
| 1138 | 1145 |
| 1146 Condition DecodeImm19BranchCondition(int32_t instr) { |
| 1147 return static_cast<Condition>((instr & kCondMask) >> kCondShift); |
| 1148 } |
| 1149 |
| 1150 int32_t EncodeImm19BranchCondition(Condition cond, int32_t instr) { |
| 1151 const int32_t c_imm = static_cast<int32_t>(cond); |
| 1152 return (instr & ~kCondMask) | (c_imm << kCondShift); |
| 1153 } |
| 1154 |
| 1155 int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr) { |
| 1156 const int32_t imm32 = static_cast<int32_t>(imm); |
| 1157 const int32_t off = (((imm32 >> 2) << kImm26Shift) & kImm26Mask); |
| 1158 return (instr & ~kImm26Mask) | off; |
| 1159 } |
| 1160 |
| 1161 int64_t DecodeImm26BranchOffset(int32_t instr) { |
| 1162 const int32_t off = (((instr & kImm26Mask) >> kImm26Shift) << 6) >> 4; |
| 1163 return static_cast<int64_t>(off); |
| 1164 } |
| 1165 |
| 1139 void EmitCompareAndBranch(CompareAndBranchOp op, Register rt, int64_t imm, | 1166 void EmitCompareAndBranch(CompareAndBranchOp op, Register rt, int64_t imm, |
| 1140 OperandSize sz) { | 1167 OperandSize sz) { |
| 1141 ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord)); | 1168 ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord)); |
| 1142 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); | 1169 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); |
| 1143 ASSERT((rt != SP) && (rt != R31)); | 1170 ASSERT((rt != SP) && (rt != R31)); |
| 1144 const Register crt = ConcreteRegister(rt); | 1171 const Register crt = ConcreteRegister(rt); |
| 1145 const int32_t size = (sz == kDoubleWord) ? B31 : 0; | 1172 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 1146 const int32_t encoded_offset = EncodeImm19BranchOffset(imm, 0); | 1173 const int32_t encoded_offset = EncodeImm19BranchOffset(imm, 0); |
| 1147 const int32_t encoding = | 1174 const int32_t encoding = |
| 1148 op | size | | 1175 op | size | |
| 1149 (static_cast<int32_t>(crt) << kRtShift) | | 1176 (static_cast<int32_t>(crt) << kRtShift) | |
| 1150 encoded_offset; | 1177 encoded_offset; |
| 1151 Emit(encoding); | 1178 Emit(encoding); |
| 1152 } | 1179 } |
| 1153 | 1180 |
| 1154 void EmitConditionalBranch(ConditionalBranchOp op, Condition cond, | 1181 void EmitConditionalBranch(ConditionalBranchOp op, Condition cond, |
| 1155 int64_t imm) { | 1182 int64_t imm) { |
| 1156 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); | 1183 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); |
| 1157 const int32_t encoding = | 1184 const int32_t encoding = |
| 1158 op | | 1185 op | |
| 1159 (static_cast<int32_t>(cond) << kCondShift) | | 1186 (static_cast<int32_t>(cond) << kCondShift) | |
| 1160 (((imm >> 2) << kImm19Shift) & kImm19Mask); | 1187 (((imm >> 2) << kImm19Shift) & kImm19Mask); |
| 1161 Emit(encoding); | 1188 Emit(encoding); |
| 1162 } | 1189 } |
| 1163 | 1190 |
| 1191 void EmitFarConditionalBranch(ConditionalBranchOp op, |
| 1192 Condition cond, |
| 1193 int64_t offset) { |
| 1194 EmitConditionalBranch(op, InvertCondition(cond), 2 * Instr::kInstrSize); |
| 1195 b(offset); |
| 1196 } |
| 1197 |
| 1164 bool CanEncodeImm19BranchOffset(int64_t offset) { | 1198 bool CanEncodeImm19BranchOffset(int64_t offset) { |
| 1165 ASSERT(Utils::IsAligned(offset, 4)); | 1199 ASSERT(Utils::IsAligned(offset, 4)); |
| 1166 return Utils::IsInt(21, offset); | 1200 return Utils::IsInt(21, offset); |
| 1167 } | 1201 } |
| 1168 | 1202 |
| 1169 // TODO(zra): Implement far branches. Requires loading large immediates. | |
| 1170 void EmitBranch(ConditionalBranchOp op, Condition cond, Label* label) { | 1203 void EmitBranch(ConditionalBranchOp op, Condition cond, Label* label) { |
| 1171 if (label->IsBound()) { | 1204 if (label->IsBound()) { |
| 1172 const int64_t dest = label->Position() - buffer_.Size(); | 1205 const int64_t dest = label->Position() - buffer_.Size(); |
| 1173 ASSERT(CanEncodeImm19BranchOffset(dest)); | 1206 if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) { |
| 1174 EmitConditionalBranch(op, cond, dest); | 1207 EmitFarConditionalBranch(op, cond, dest); |
| 1208 } else { |
| 1209 EmitConditionalBranch(op, cond, dest); |
| 1210 } |
| 1175 } else { | 1211 } else { |
| 1176 const int64_t position = buffer_.Size(); | 1212 const int64_t position = buffer_.Size(); |
| 1177 ASSERT(CanEncodeImm19BranchOffset(position)); | 1213 if (use_far_branches()) { |
| 1178 EmitConditionalBranch(op, cond, label->position_); | 1214 EmitFarConditionalBranch(op, cond, label->position_); |
| 1215 } else { |
| 1216 EmitConditionalBranch(op, cond, label->position_); |
| 1217 } |
| 1179 label->LinkTo(position); | 1218 label->LinkTo(position); |
| 1180 } | 1219 } |
| 1181 } | 1220 } |
| 1182 | 1221 |
| 1222 bool CanEncodeImm26BranchOffset(int64_t offset) { |
| 1223 ASSERT(Utils::IsAligned(offset, 4)); |
| 1224 return Utils::IsInt(26, offset); |
| 1225 } |
| 1226 |
| 1227 void EmitUnconditionalBranchOp(UnconditionalBranchOp op, int64_t offset) { |
| 1228 ASSERT(CanEncodeImm26BranchOffset(offset)); |
| 1229 const int32_t off = (offset >> 2) << kImm26Shift; |
| 1230 const int32_t encoding = op | off; |
| 1231 Emit(encoding); |
| 1232 } |
| 1233 |
| 1183 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { | 1234 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { |
| 1184 ASSERT((rn != SP) && (rn != R31)); | 1235 ASSERT((rn != SP) && (rn != R31)); |
| 1185 const Register crn = ConcreteRegister(rn); | 1236 const Register crn = ConcreteRegister(rn); |
| 1186 const int32_t encoding = | 1237 const int32_t encoding = |
| 1187 op | (static_cast<int32_t>(crn) << kRnShift); | 1238 op | (static_cast<int32_t>(crn) << kRnShift); |
| 1188 Emit(encoding); | 1239 Emit(encoding); |
| 1189 } | 1240 } |
| 1190 | 1241 |
| 1191 void EmitExceptionGenOp(ExceptionGenOp op, uint16_t imm) { | 1242 void EmitExceptionGenOp(ExceptionGenOp op, uint16_t imm) { |
| 1192 const int32_t encoding = | 1243 const int32_t encoding = |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1346 Register value, | 1397 Register value, |
| 1347 Label* no_update); | 1398 Label* no_update); |
| 1348 | 1399 |
| 1349 DISALLOW_ALLOCATION(); | 1400 DISALLOW_ALLOCATION(); |
| 1350 DISALLOW_COPY_AND_ASSIGN(Assembler); | 1401 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 1351 }; | 1402 }; |
| 1352 | 1403 |
| 1353 } // namespace dart | 1404 } // namespace dart |
| 1354 | 1405 |
| 1355 #endif // VM_ASSEMBLER_ARM64_H_ | 1406 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |