| 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/object.h" | 16 #include "vm/object.h" |
| 16 #include "vm/simulator.h" | 17 #include "vm/simulator.h" |
| 17 | 18 |
| 18 namespace dart { | 19 namespace dart { |
| 19 | 20 |
| 20 // Forward declarations. | 21 // Forward declarations. |
| 21 class RuntimeEntry; | 22 class RuntimeEntry; |
| 22 | 23 |
| 23 // TODO(zra): Label, Address, and FieldAddress are copied from ARM, | 24 // TODO(zra): Label, Address, and FieldAddress are copied from ARM, |
| 24 // they must be adapted to ARM64. | 25 // they must be adapted to ARM64. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 type_ = other.type_; | 81 type_ = other.type_; |
| 81 base_ = other.base_; | 82 base_ = other.base_; |
| 82 return *this; | 83 return *this; |
| 83 } | 84 } |
| 84 | 85 |
| 85 enum AddressType { | 86 enum AddressType { |
| 86 Offset, | 87 Offset, |
| 87 PreIndex, | 88 PreIndex, |
| 88 PostIndex, | 89 PostIndex, |
| 89 Reg, | 90 Reg, |
| 91 PCOffset, |
| 92 Unknown, |
| 90 }; | 93 }; |
| 91 | 94 |
| 92 // Offset is in bytes. For the unsigned imm12 case, we unscale based on the | 95 // Offset is in bytes. For the unsigned imm12 case, we unscale based on the |
| 93 // operand size, and assert that offset is aligned accordingly. | 96 // operand size, and assert that offset is aligned accordingly. |
| 94 // For the smaller signed imm9 case, the offset is the number of bytes, but | 97 // For the smaller signed imm9 case, the offset is the number of bytes, but |
| 95 // is unscaled. | 98 // is unscaled. |
| 96 Address(Register rn, int32_t offset = 0, AddressType at = Offset, | 99 Address(Register rn, int32_t offset = 0, AddressType at = Offset, |
| 97 OperandSize sz = kDoubleWord) { | 100 OperandSize sz = kDoubleWord) { |
| 98 ASSERT((rn != R31) && (rn != ZR)); | 101 ASSERT((rn != R31) && (rn != ZR)); |
| 99 const Register crn = ConcreteRegister(rn); | 102 const Register crn = ConcreteRegister(rn); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 110 int32_t idx = (at == PostIndex) ? B10 : (B11 | B10); | 113 int32_t idx = (at == PostIndex) ? B10 : (B11 | B10); |
| 111 encoding_ = | 114 encoding_ = |
| 112 idx | | 115 idx | |
| 113 ((offset & 0x1ff) << kImm9Shift) | | 116 ((offset & 0x1ff) << kImm9Shift) | |
| 114 (static_cast<int32_t>(crn) << kRnShift); | 117 (static_cast<int32_t>(crn) << kRnShift); |
| 115 } | 118 } |
| 116 type_ = at; | 119 type_ = at; |
| 117 base_ = crn; | 120 base_ = crn; |
| 118 } | 121 } |
| 119 | 122 |
| 120 // TODO(zra): Write CanHoldOffset(int32_t off, AddressType, OperandSize). | 123 static bool CanHoldOffset(int32_t offset, AddressType at = Offset, |
| 121 // TODO(zra): Write constructor for PC-relative load address. | 124 OperandSize sz = kDoubleWord) { |
| 125 if (at == Offset) { |
| 126 // Fits in 12 bit unsigned and right alignment for sz. |
| 127 const int32_t scale = Log2OperandSizeBytes(sz); |
| 128 return Utils::IsUint(12 + scale, offset) && |
| 129 (offset == ((offset >> scale) << scale)); |
| 130 } else if (at == PCOffset) { |
| 131 return Utils::IsInt(21, offset) && |
| 132 (offset == ((offset >> 2) << 2)); |
| 133 } else { |
| 134 ASSERT((at == PreIndex) || (at == PostIndex)); |
| 135 return Utils::IsInt(9, offset); |
| 136 } |
| 137 } |
| 138 |
| 139 // PC-relative load address. |
| 140 static Address PC(int32_t pc_off) { |
| 141 ASSERT(CanHoldOffset(pc_off, PCOffset)); |
| 142 Address addr; |
| 143 addr.encoding_ = (((pc_off >> 2) & kImm19Mask) << kImm19Shift); |
| 144 addr.base_ = kNoRegister; |
| 145 addr.type_ = PCOffset; |
| 146 return addr; |
| 147 } |
| 122 | 148 |
| 123 // Base register rn with offset rm. rm is sign-extended according to ext. | 149 // Base register rn with offset rm. rm is sign-extended according to ext. |
| 124 // If ext is UXTX, rm may be optionally scaled by the | 150 // If ext is UXTX, rm may be optionally scaled by the |
| 125 // Log2OperandSize (specified by the instruction). | 151 // Log2OperandSize (specified by the instruction). |
| 126 Address(Register rn, Register rm, Extend ext = UXTX, bool scaled = false) { | 152 Address(Register rn, Register rm, Extend ext = UXTX, bool scaled = false) { |
| 127 ASSERT((rn != R31) && (rn != ZR)); | 153 ASSERT((rn != R31) && (rn != ZR)); |
| 128 ASSERT((rm != R31) && (rm != SP)); | 154 ASSERT((rm != R31) && (rm != SP)); |
| 129 ASSERT(!scaled || (ext == UXTX)); // Can only scale when ext = UXTX. | 155 ASSERT(!scaled || (ext == UXTX)); // Can only scale when ext = UXTX. |
| 130 ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX)); | 156 ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX)); |
| 131 const Register crn = ConcreteRegister(rn); | 157 const Register crn = ConcreteRegister(rn); |
| 132 const Register crm = ConcreteRegister(rm); | 158 const Register crm = ConcreteRegister(rm); |
| 133 const int32_t s = scaled ? B12 : 0; | 159 const int32_t s = scaled ? B12 : 0; |
| 134 encoding_ = | 160 encoding_ = |
| 135 B21 | B11 | s | | 161 B21 | B11 | s | |
| 136 (static_cast<int32_t>(crn) << kRnShift) | | 162 (static_cast<int32_t>(crn) << kRnShift) | |
| 137 (static_cast<int32_t>(crm) << kRmShift) | | 163 (static_cast<int32_t>(crm) << kRmShift) | |
| 138 (static_cast<int32_t>(ext) << kExtendTypeShift); | 164 (static_cast<int32_t>(ext) << kExtendTypeShift); |
| 139 type_ = Reg; | 165 type_ = Reg; |
| 140 base_ = crn; | 166 base_ = crn; |
| 141 } | 167 } |
| 142 | 168 |
| 143 private: | 169 private: |
| 144 uint32_t encoding() const { return encoding_; } | 170 uint32_t encoding() const { return encoding_; } |
| 145 AddressType type() const { return type_; } | 171 AddressType type() const { return type_; } |
| 146 Register base() const { return base_; } | 172 Register base() const { return base_; } |
| 147 | 173 |
| 174 Address() : encoding_(0), type_(Unknown), base_(kNoRegister) {} |
| 175 |
| 148 uint32_t encoding_; | 176 uint32_t encoding_; |
| 149 AddressType type_; | 177 AddressType type_; |
| 150 Register base_; | 178 Register base_; |
| 151 | 179 |
| 152 friend class Assembler; | 180 friend class Assembler; |
| 153 }; | 181 }; |
| 154 | 182 |
| 155 | 183 |
| 156 class FieldAddress : public Address { | 184 class FieldAddress : public Address { |
| 157 public: | 185 public: |
| 158 FieldAddress(Register base, int32_t disp) | 186 FieldAddress(Register base, int32_t disp) |
| 159 : Address(base, disp - kHeapObjectTag) { } | 187 : Address(base, disp - kHeapObjectTag) { } |
| 160 | 188 |
| 161 FieldAddress(const FieldAddress& other) : Address(other) { } | 189 FieldAddress(const FieldAddress& other) : Address(other) { } |
| 162 | 190 |
| 163 FieldAddress& operator=(const FieldAddress& other) { | 191 FieldAddress& operator=(const FieldAddress& other) { |
| 164 Address::operator=(other); | 192 Address::operator=(other); |
| 165 return *this; | 193 return *this; |
| 166 } | 194 } |
| 167 }; | 195 }; |
| 168 | 196 |
| 169 | 197 |
| 170 class Operand : public ValueObject { | 198 class Operand : public ValueObject { |
| 171 public: | 199 public: |
| 200 enum OperandType { |
| 201 Shifted, |
| 202 Extended, |
| 203 Immediate, |
| 204 BitfieldImm, |
| 205 Unknown, |
| 206 }; |
| 207 |
| 172 // Data-processing operand - Uninitialized. | 208 // Data-processing operand - Uninitialized. |
| 173 Operand() : encoding_(-1), type_(Unknown) { } | 209 Operand() : encoding_(-1), type_(Unknown) { } |
| 174 | 210 |
| 175 // Data-processing operands - Copy constructor. | 211 // Data-processing operands - Copy constructor. |
| 176 Operand(const Operand& other) | 212 Operand(const Operand& other) |
| 177 : ValueObject(), encoding_(other.encoding_), type_(other.type_) { } | 213 : ValueObject(), encoding_(other.encoding_), type_(other.type_) { } |
| 178 | 214 |
| 179 Operand& operator=(const Operand& other) { | 215 Operand& operator=(const Operand& other) { |
| 180 type_ = other.type_; | 216 type_ = other.type_; |
| 181 encoding_ = other.encoding_; | 217 encoding_ = other.encoding_; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 } else { | 254 } else { |
| 219 // imm only has bits in [12, 24) set. | 255 // imm only has bits in [12, 24) set. |
| 220 ASSERT(((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12))); | 256 ASSERT(((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12))); |
| 221 encoding_ = B22 | ((imm >> 12) << kImm12Shift); | 257 encoding_ = B22 | ((imm >> 12) << kImm12Shift); |
| 222 } | 258 } |
| 223 type_ = Immediate; | 259 type_ = Immediate; |
| 224 } | 260 } |
| 225 | 261 |
| 226 // Encodes the value of an immediate for a logical operation. | 262 // Encodes the value of an immediate for a logical operation. |
| 227 // Since these values are difficult to craft by hand, instead pass the | 263 // Since these values are difficult to craft by hand, instead pass the |
| 228 // logical mask to the function Assembler::IsImmLogical to get n, imm_s, and | 264 // logical mask to the function IsImmLogical to get n, imm_s, and |
| 229 // imm_r. | 265 // imm_r. |
| 230 Operand(uint8_t n, int8_t imm_s, int8_t imm_r) { | 266 Operand(uint8_t n, int8_t imm_s, int8_t imm_r) { |
| 231 ASSERT((n == 1) || (n == 0)); | 267 ASSERT((n == 1) || (n == 0)); |
| 232 ASSERT(Utils::IsUint(6, imm_s) && Utils::IsUint(6, imm_r)); | 268 ASSERT(Utils::IsUint(6, imm_s) && Utils::IsUint(6, imm_r)); |
| 233 type_ = BitfieldImm; | 269 type_ = BitfieldImm; |
| 234 encoding_ = | 270 encoding_ = |
| 235 (static_cast<int32_t>(n) << kNShift) | | 271 (static_cast<int32_t>(n) << kNShift) | |
| 236 (static_cast<int32_t>(imm_s) << kImmSShift) | | 272 (static_cast<int32_t>(imm_s) << kImmSShift) | |
| 237 (static_cast<int32_t>(imm_r) << kImmRShift); | 273 (static_cast<int32_t>(imm_r) << kImmRShift); |
| 238 } | 274 } |
| 239 | 275 |
| 240 enum OperandType { | 276 // Test if a given value can be encoded in the immediate field of a logical |
| 241 Shifted, | 277 // instruction. |
| 242 Extended, | 278 // If it can be encoded, the function returns true, and values pointed to by |
| 243 Immediate, | 279 // n, imm_s and imm_r are updated with immediates encoded in the format |
| 244 BitfieldImm, | 280 // required by the corresponding fields in the logical instruction. |
| 245 Unknown, | 281 // If it can't be encoded, the function returns false, and the operand is |
| 246 }; | 282 // undefined. |
| 283 static bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op); |
| 284 |
| 285 // An immediate imm can be an operand to add/sub when the return value is |
| 286 // Immediate, or a logical operation over sz bits when the return value is |
| 287 // BitfieldImm. If the return value is Unknown, then the immediate can't be |
| 288 // used as an operand in either instruction. The encoded operand is written |
| 289 // to op. |
| 290 static OperandType CanHold(int64_t imm, uint8_t sz, Operand* op) { |
| 291 ASSERT(op != NULL); |
| 292 ASSERT((sz == kXRegSizeInBits) || (sz == kWRegSizeInBits)); |
| 293 if (Utils::IsUint(12, imm)) { |
| 294 op->encoding_ = imm << kImm12Shift; |
| 295 op->type_ = Immediate; |
| 296 } else if (((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12))) { |
| 297 op->encoding_ = B22 | ((imm >> 12) << kImm12Shift); |
| 298 op->type_ = Immediate; |
| 299 } else if (IsImmLogical(imm, sz, op)) { |
| 300 op->type_ = BitfieldImm; |
| 301 } else { |
| 302 op->encoding_ = 0; |
| 303 op->type_ = Unknown; |
| 304 } |
| 305 return op->type_; |
| 306 } |
| 247 | 307 |
| 248 private: | 308 private: |
| 249 uint32_t encoding() const { | 309 uint32_t encoding() const { |
| 250 return encoding_; | 310 return encoding_; |
| 251 } | 311 } |
| 252 OperandType type() const { | 312 OperandType type() const { |
| 253 return type_; | 313 return type_; |
| 254 } | 314 } |
| 255 | 315 |
| 256 uint32_t encoding_; | 316 uint32_t encoding_; |
| 257 OperandType type_; | 317 OperandType type_; |
| 258 | 318 |
| 259 friend class Assembler; | 319 friend class Assembler; |
| 260 }; | 320 }; |
| 261 | 321 |
| 262 | 322 |
| 263 class Assembler : public ValueObject { | 323 class Assembler : public ValueObject { |
| 264 public: | 324 public: |
| 265 explicit Assembler(bool use_far_branches = false) | 325 explicit Assembler(bool use_far_branches = false); |
| 266 : buffer_(), | |
| 267 object_pool_(GrowableObjectArray::Handle()), | |
| 268 prologue_offset_(-1), | |
| 269 use_far_branches_(use_far_branches), | |
| 270 comments_() { } | |
| 271 ~Assembler() { } | 326 ~Assembler() { } |
| 272 | 327 |
| 273 void PopRegister(Register r) { | 328 void PopRegister(Register r) { |
| 274 UNIMPLEMENTED(); | 329 UNIMPLEMENTED(); |
| 275 } | 330 } |
| 276 | 331 |
| 277 void Drop(intptr_t stack_elements) { | 332 void Drop(intptr_t stack_elements) { |
| 278 UNIMPLEMENTED(); | 333 UNIMPLEMENTED(); |
| 279 } | 334 } |
| 280 | 335 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 // PC relative immediate add. imm is in bytes. | 412 // PC relative immediate add. imm is in bytes. |
| 358 void adr(Register rd, int64_t imm) { | 413 void adr(Register rd, int64_t imm) { |
| 359 EmitPCRelOp(ADR, rd, imm); | 414 EmitPCRelOp(ADR, rd, imm); |
| 360 } | 415 } |
| 361 | 416 |
| 362 // Logical immediate operations. | 417 // Logical immediate operations. |
| 363 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer | 418 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer |
| 364 // sequence on failure. | 419 // sequence on failure. |
| 365 void andi(Register rd, Register rn, uint64_t imm) { | 420 void andi(Register rd, Register rn, uint64_t imm) { |
| 366 Operand imm_op; | 421 Operand imm_op; |
| 367 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 422 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 368 ASSERT(immok); | 423 ASSERT(immok); |
| 369 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); | 424 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); |
| 370 } | 425 } |
| 371 void orri(Register rd, Register rn, uint64_t imm) { | 426 void orri(Register rd, Register rn, uint64_t imm) { |
| 372 Operand imm_op; | 427 Operand imm_op; |
| 373 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 428 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 374 ASSERT(immok); | 429 ASSERT(immok); |
| 375 EmitLogicalImmOp(ORRI, rd, rn, imm_op, kDoubleWord); | 430 EmitLogicalImmOp(ORRI, rd, rn, imm_op, kDoubleWord); |
| 376 } | 431 } |
| 377 void eori(Register rd, Register rn, uint64_t imm) { | 432 void eori(Register rd, Register rn, uint64_t imm) { |
| 378 Operand imm_op; | 433 Operand imm_op; |
| 379 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 434 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 380 ASSERT(immok); | 435 ASSERT(immok); |
| 381 EmitLogicalImmOp(EORI, rd, rn, imm_op, kDoubleWord); | 436 EmitLogicalImmOp(EORI, rd, rn, imm_op, kDoubleWord); |
| 382 } | 437 } |
| 383 void andis(Register rd, Register rn, uint64_t imm) { | 438 void andis(Register rd, Register rn, uint64_t imm) { |
| 384 Operand imm_op; | 439 Operand imm_op; |
| 385 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 440 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 386 ASSERT(immok); | 441 ASSERT(immok); |
| 387 EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kDoubleWord); | 442 EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kDoubleWord); |
| 388 } | 443 } |
| 389 | 444 |
| 390 // Logical (shifted) register operations. | 445 // Logical (shifted) register operations. |
| 391 void and_(Register rd, Register rn, Operand o) { | 446 void and_(Register rd, Register rn, Operand o) { |
| 392 EmitLogicalShiftOp(AND, rd, rn, o, kDoubleWord); | 447 EmitLogicalShiftOp(AND, rd, rn, o, kDoubleWord); |
| 393 } | 448 } |
| 394 void bic(Register rd, Register rn, Operand o) { | 449 void bic(Register rd, Register rn, Operand o) { |
| 395 EmitLogicalShiftOp(BIC, rd, rn, o, kDoubleWord); | 450 EmitLogicalShiftOp(BIC, rd, rn, o, kDoubleWord); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 EmitMiscDP2Source(LSRV, rd, rn, rm, kDoubleWord); | 482 EmitMiscDP2Source(LSRV, rd, rn, rm, kDoubleWord); |
| 428 } | 483 } |
| 429 void asrv(Register rd, Register rn, Register rm) { | 484 void asrv(Register rd, Register rn, Register rm) { |
| 430 EmitMiscDP2Source(ASRV, rd, rn, rm, kDoubleWord); | 485 EmitMiscDP2Source(ASRV, rd, rn, rm, kDoubleWord); |
| 431 } | 486 } |
| 432 void madd(Register rd, Register rn, Register rm, Register ra) { | 487 void madd(Register rd, Register rn, Register rm, Register ra) { |
| 433 EmitMiscDP3Source(MADD, rd, rn, rm, ra, kDoubleWord); | 488 EmitMiscDP3Source(MADD, rd, rn, rm, ra, kDoubleWord); |
| 434 } | 489 } |
| 435 | 490 |
| 436 // Move wide immediate. | 491 // Move wide immediate. |
| 437 void movk(Register rd, int32_t imm, int32_t hw_idx) { | 492 void movk(Register rd, uint16_t imm, int hw_idx) { |
| 438 ASSERT(rd != SP); | 493 ASSERT(rd != SP); |
| 439 const Register crd = ConcreteRegister(rd); | 494 const Register crd = ConcreteRegister(rd); |
| 440 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); | 495 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); |
| 441 } | 496 } |
| 442 void movn(Register rd, int32_t imm, int32_t hw_idx) { | 497 void movn(Register rd, uint16_t imm, int hw_idx) { |
| 443 ASSERT(rd != SP); | 498 ASSERT(rd != SP); |
| 444 const Register crd = ConcreteRegister(rd); | 499 const Register crd = ConcreteRegister(rd); |
| 445 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); | 500 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); |
| 446 } | 501 } |
| 447 void movz(Register rd, int32_t imm, int32_t hw_idx) { | 502 void movz(Register rd, uint16_t imm, int hw_idx) { |
| 448 ASSERT(rd != SP); | 503 ASSERT(rd != SP); |
| 449 const Register crd = ConcreteRegister(rd); | 504 const Register crd = ConcreteRegister(rd); |
| 450 EmitMoveWideOp(MOVZ, crd, imm, hw_idx, kDoubleWord); | 505 EmitMoveWideOp(MOVZ, crd, imm, hw_idx, kDoubleWord); |
| 451 } | 506 } |
| 452 | 507 |
| 453 // Loads and Stores. | 508 // Loads and Stores. |
| 454 void ldr(Register rt, Address a) { | 509 void ldr(Register rt, Address a) { |
| 455 // If we are doing pre-/post-indexing, and the base and result registers | 510 if (a.type() == Address::PCOffset) { |
| 456 // are the same, then the result of the load will be clobbered by the | 511 EmitLoadRegLiteral(LDRpc, rt, a, kDoubleWord); |
| 457 // writeback, which is unlikely to be useful. | 512 } else { |
| 458 ASSERT(((a.type() != Address::PreIndex) && | 513 // If we are doing pre-/post-indexing, and the base and result registers |
| 459 (a.type() != Address::PostIndex)) || | 514 // are the same, then the result of the load will be clobbered by the |
| 460 (rt != a.base())); | 515 // writeback, which is unlikely to be useful. |
| 461 EmitLoadStoreReg(LDR, rt, a, kDoubleWord); | 516 ASSERT(((a.type() != Address::PreIndex) && |
| 517 (a.type() != Address::PostIndex)) || |
| 518 (rt != a.base())); |
| 519 EmitLoadStoreReg(LDR, rt, a, kDoubleWord); |
| 520 } |
| 462 } | 521 } |
| 463 void str(Register rt, Address a) { | 522 void str(Register rt, Address a) { |
| 464 EmitLoadStoreReg(STR, rt, a, kDoubleWord); | 523 EmitLoadStoreReg(STR, rt, a, kDoubleWord); |
| 465 } | 524 } |
| 466 | 525 |
| 467 // Comparison. | 526 // Comparison. |
| 468 // rn cmp o. | 527 // rn cmp o. |
| 469 void cmp(Register rn, Operand o) { | 528 void cmp(Register rn, Operand o) { |
| 470 subs(ZR, rn, o); | 529 subs(ZR, rn, o); |
| 471 } | 530 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 } | 565 } |
| 507 void neg(Register rd, Register rm) { | 566 void neg(Register rd, Register rm) { |
| 508 sub(rd, ZR, Operand(rm)); | 567 sub(rd, ZR, Operand(rm)); |
| 509 } | 568 } |
| 510 void negs(Register rd, Register rm) { | 569 void negs(Register rd, Register rm) { |
| 511 subs(rd, ZR, Operand(rm)); | 570 subs(rd, ZR, Operand(rm)); |
| 512 } | 571 } |
| 513 void mul(Register rd, Register rn, Register rm) { | 572 void mul(Register rd, Register rn, Register rm) { |
| 514 madd(rd, rn, rm, ZR); | 573 madd(rd, rn, rm, ZR); |
| 515 } | 574 } |
| 575 void Push(Register reg) { |
| 576 str(reg, Address(SP, -1 * kWordSize, Address::PreIndex)); |
| 577 } |
| 578 void Pop(Register reg) { |
| 579 ldr(reg, Address(SP, 1 * kWordSize, Address::PostIndex)); |
| 580 } |
| 581 |
| 582 // Object pool, loading from pool, etc. |
| 583 void LoadPoolPointer(Register pp) { |
| 584 const intptr_t object_pool_pc_dist = |
| 585 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 586 CodeSize(); |
| 587 // PP <- Read(PC - object_pool_pc_dist). |
| 588 ldr(pp, Address::PC(-object_pool_pc_dist)); |
| 589 } |
| 590 |
| 591 enum Patchability { |
| 592 kPatchable, |
| 593 kNotPatchable, |
| 594 }; |
| 595 |
| 596 void LoadWordFromPoolOffset(Register dst, Register pp, uint32_t offset); |
| 597 intptr_t FindObject(const Object& obj, Patchability patchable); |
| 598 intptr_t FindImmediate(int64_t imm); |
| 599 bool CanLoadObjectFromPool(const Object& object); |
| 600 bool CanLoadImmediateFromPool(int64_t imm, Register pp); |
| 601 void LoadObject(Register dst, const Object& obj, Register pp); |
| 602 void LoadImmediate(Register reg, int64_t imm, Register pp); |
| 516 | 603 |
| 517 private: | 604 private: |
| 518 AssemblerBuffer buffer_; // Contains position independent code. | 605 AssemblerBuffer buffer_; // Contains position independent code. |
| 519 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. | 606 |
| 607 // Objects and patchable jump targets. |
| 608 GrowableObjectArray& object_pool_; |
| 609 |
| 610 // Patchability of pool entries. |
| 611 GrowableArray<Patchability> patchable_pool_entries_; |
| 612 |
| 613 // Pair type parameter for DirectChainedHashMap. |
| 614 class ObjIndexPair { |
| 615 public: |
| 616 // TODO(zra): A WeakTable should be used here instead, but then it would |
| 617 // also have to be possible to register and de-register WeakTables with the |
| 618 // heap. Also, the Assembler would need to become a StackResource. |
| 619 // Issue 13305. In the meantime... |
| 620 // CAUTION: the RawObject* below is only safe because: |
| 621 // The HashMap that will use this pair type will not contain any RawObject* |
| 622 // keys that are not in the object_pool_ array. Since the keys will be |
| 623 // visited by the GC when it visits the object_pool_, and since all objects |
| 624 // in the object_pool_ are Old (and so will not be moved) the GC does not |
| 625 // also need to visit the keys here in the HashMap. |
| 626 |
| 627 // Typedefs needed for the DirectChainedHashMap template. |
| 628 typedef RawObject* Key; |
| 629 typedef intptr_t Value; |
| 630 typedef ObjIndexPair Pair; |
| 631 |
| 632 ObjIndexPair(Key key, Value value) : key_(key), value_(value) { } |
| 633 |
| 634 static Key KeyOf(Pair kv) { return kv.key_; } |
| 635 |
| 636 static Value ValueOf(Pair kv) { return kv.value_; } |
| 637 |
| 638 static intptr_t Hashcode(Key key) { |
| 639 return reinterpret_cast<intptr_t>(key) >> kObjectAlignmentLog2; |
| 640 } |
| 641 |
| 642 static inline bool IsKeyEqual(Pair kv, Key key) { |
| 643 return kv.key_ == key; |
| 644 } |
| 645 |
| 646 private: |
| 647 Key key_; |
| 648 Value value_; |
| 649 }; |
| 650 |
| 651 // Hashmap for fast lookup in object pool. |
| 652 DirectChainedHashMap<ObjIndexPair> object_pool_index_table_; |
| 653 |
| 520 int32_t prologue_offset_; | 654 int32_t prologue_offset_; |
| 521 | 655 |
| 522 bool use_far_branches_; | 656 bool use_far_branches_; |
| 523 | 657 |
| 524 class CodeComment : public ZoneAllocated { | 658 class CodeComment : public ZoneAllocated { |
| 525 public: | 659 public: |
| 526 CodeComment(intptr_t pc_offset, const String& comment) | 660 CodeComment(intptr_t pc_offset, const String& comment) |
| 527 : pc_offset_(pc_offset), comment_(comment) { } | 661 : pc_offset_(pc_offset), comment_(comment) { } |
| 528 | 662 |
| 529 intptr_t pc_offset() const { return pc_offset_; } | 663 intptr_t pc_offset() const { return pc_offset_; } |
| 530 const String& comment() const { return comment_; } | 664 const String& comment() const { return comment_; } |
| 531 | 665 |
| 532 private: | 666 private: |
| 533 intptr_t pc_offset_; | 667 intptr_t pc_offset_; |
| 534 const String& comment_; | 668 const String& comment_; |
| 535 | 669 |
| 536 DISALLOW_COPY_AND_ASSIGN(CodeComment); | 670 DISALLOW_COPY_AND_ASSIGN(CodeComment); |
| 537 }; | 671 }; |
| 538 | 672 |
| 539 GrowableArray<CodeComment*> comments_; | 673 GrowableArray<CodeComment*> comments_; |
| 540 | 674 |
| 541 bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op); | |
| 542 | |
| 543 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, | 675 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, |
| 544 Register rd, Register rn, Operand o) { | 676 Register rd, Register rn, Operand o) { |
| 545 ASSERT((rd != R31) && (rn != R31)); | 677 ASSERT((rd != R31) && (rn != R31)); |
| 546 const Register crd = ConcreteRegister(rd); | 678 const Register crd = ConcreteRegister(rd); |
| 547 const Register crn = ConcreteRegister(rn); | 679 const Register crn = ConcreteRegister(rn); |
| 548 if (o.type() == Operand::Immediate) { | 680 if (o.type() == Operand::Immediate) { |
| 549 ASSERT(rn != ZR); | 681 ASSERT(rn != ZR); |
| 550 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); | 682 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); |
| 551 } else if (o.type() == Operand::Shifted) { | 683 } else if (o.type() == Operand::Shifted) { |
| 552 ASSERT((rd != SP) && (rn != SP)); | 684 ASSERT((rd != SP) && (rn != SP)); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 label->LinkTo(position); | 805 label->LinkTo(position); |
| 674 } | 806 } |
| 675 } | 807 } |
| 676 | 808 |
| 677 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { | 809 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { |
| 678 const int32_t encoding = | 810 const int32_t encoding = |
| 679 op | (static_cast<int32_t>(rn) << kRnShift); | 811 op | (static_cast<int32_t>(rn) << kRnShift); |
| 680 Emit(encoding); | 812 Emit(encoding); |
| 681 } | 813 } |
| 682 | 814 |
| 683 void EmitMoveWideOp(MoveWideOp op, Register rd, int32_t imm, int32_t hw_idx, | 815 void EmitMoveWideOp(MoveWideOp op, Register rd, uint16_t imm, int hw_idx, |
| 684 OperandSize sz) { | 816 OperandSize sz) { |
| 685 ASSERT(Utils::IsUint(16, imm)); | |
| 686 ASSERT((hw_idx >= 0) && (hw_idx <= 3)); | 817 ASSERT((hw_idx >= 0) && (hw_idx <= 3)); |
| 687 ASSERT((sz == kDoubleWord) || (sz == kWord)); | 818 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 688 const int32_t size = (sz == kDoubleWord) ? B31 : 0; | 819 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 689 const int32_t encoding = | 820 const int32_t encoding = |
| 690 op | size | | 821 op | size | |
| 691 (static_cast<int32_t>(rd) << kRdShift) | | 822 (static_cast<int32_t>(rd) << kRdShift) | |
| 692 (hw_idx << kHWShift) | | 823 (static_cast<int32_t>(hw_idx) << kHWShift) | |
| 693 (imm << kImm16Shift); | 824 (static_cast<int32_t>(imm) << kImm16Shift); |
| 694 Emit(encoding); | 825 Emit(encoding); |
| 695 } | 826 } |
| 696 | 827 |
| 697 void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a, | 828 void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a, |
| 698 OperandSize sz) { | 829 OperandSize sz) { |
| 699 const int32_t size = Log2OperandSizeBytes(sz); | 830 const int32_t size = Log2OperandSizeBytes(sz); |
| 700 const int32_t encoding = | 831 const int32_t encoding = |
| 701 op | (size << kSzShift) | | 832 op | (size << kSzShift) | |
| 702 (static_cast<int32_t>(rt) << kRtShift) | | 833 (static_cast<int32_t>(rt) << kRtShift) | |
| 703 a.encoding(); | 834 a.encoding(); |
| 704 Emit(encoding); | 835 Emit(encoding); |
| 705 } | 836 } |
| 706 | 837 |
| 838 void EmitLoadRegLiteral(LoadRegLiteralOp op, Register rt, Address a, |
| 839 OperandSize sz) { |
| 840 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 841 const int32_t size = (sz == kDoubleWord) ? B30 : 0; |
| 842 const int32_t encoding = |
| 843 op | size | |
| 844 (static_cast<int32_t>(rt) << kRtShift) | |
| 845 a.encoding(); |
| 846 Emit(encoding); |
| 847 } |
| 848 |
| 707 void EmitPCRelOp(PCRelOp op, Register rd, int64_t imm) { | 849 void EmitPCRelOp(PCRelOp op, Register rd, int64_t imm) { |
| 708 ASSERT(Utils::IsInt(21, imm)); | 850 ASSERT(Utils::IsInt(21, imm)); |
| 709 ASSERT((rd != R31) && (rd != SP)); | 851 ASSERT((rd != R31) && (rd != SP)); |
| 710 const Register crd = ConcreteRegister(rd); | 852 const Register crd = ConcreteRegister(rd); |
| 711 const int32_t loimm = (imm & 0x3) << 29; | 853 const int32_t loimm = (imm & 0x3) << 29; |
| 712 const int32_t hiimm = ((imm >> 2) & kImm19Mask) << kImm19Shift; | 854 const int32_t hiimm = ((imm >> 2) & kImm19Mask) << kImm19Shift; |
| 713 const int32_t encoding = | 855 const int32_t encoding = |
| 714 op | loimm | hiimm | | 856 op | loimm | hiimm | |
| 715 (static_cast<int32_t>(crd) << kRdShift); | 857 (static_cast<int32_t>(crd) << kRdShift); |
| 716 Emit(encoding); | 858 Emit(encoding); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 Emit(encoding); | 892 Emit(encoding); |
| 751 } | 893 } |
| 752 | 894 |
| 753 DISALLOW_ALLOCATION(); | 895 DISALLOW_ALLOCATION(); |
| 754 DISALLOW_COPY_AND_ASSIGN(Assembler); | 896 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 755 }; | 897 }; |
| 756 | 898 |
| 757 } // namespace dart | 899 } // namespace dart |
| 758 | 900 |
| 759 #endif // VM_ASSEMBLER_ARM64_H_ | 901 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |