Chromium Code Reviews| 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 n, |
| 243 Immediate, | 279 // imm_s and imm_r are updated with immediates encoded in the format required |
| 244 BitfieldImm, | 280 // 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)) { | |
|
regis
2014/04/15 23:37:04
So, what is the returned op->type_ if IsImmLogical
zra
2014/04/16 15:48:16
Done.
| |
| 300 op->encoding_ = 0; | |
| 301 op->type_ = Unknown; | |
| 302 } | |
| 303 return op->type_; | |
| 304 } | |
| 247 | 305 |
| 248 private: | 306 private: |
| 249 uint32_t encoding() const { | 307 uint32_t encoding() const { |
| 250 return encoding_; | 308 return encoding_; |
| 251 } | 309 } |
| 252 OperandType type() const { | 310 OperandType type() const { |
| 253 return type_; | 311 return type_; |
| 254 } | 312 } |
| 255 | 313 |
| 256 uint32_t encoding_; | 314 uint32_t encoding_; |
| 257 OperandType type_; | 315 OperandType type_; |
| 258 | 316 |
| 259 friend class Assembler; | 317 friend class Assembler; |
| 260 }; | 318 }; |
| 261 | 319 |
| 262 | 320 |
| 263 class Assembler : public ValueObject { | 321 class Assembler : public ValueObject { |
| 264 public: | 322 public: |
| 265 explicit Assembler(bool use_far_branches = false) | 323 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() { } | 324 ~Assembler() { } |
| 272 | 325 |
| 273 void PopRegister(Register r) { | 326 void PopRegister(Register r) { |
| 274 UNIMPLEMENTED(); | 327 UNIMPLEMENTED(); |
| 275 } | 328 } |
| 276 | 329 |
| 277 void Drop(intptr_t stack_elements) { | 330 void Drop(intptr_t stack_elements) { |
| 278 UNIMPLEMENTED(); | 331 UNIMPLEMENTED(); |
| 279 } | 332 } |
| 280 | 333 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 357 // PC relative immediate add. imm is in bytes. | 410 // PC relative immediate add. imm is in bytes. |
| 358 void adr(Register rd, int64_t imm) { | 411 void adr(Register rd, int64_t imm) { |
| 359 EmitPCRelOp(ADR, rd, imm); | 412 EmitPCRelOp(ADR, rd, imm); |
| 360 } | 413 } |
| 361 | 414 |
| 362 // Logical immediate operations. | 415 // Logical immediate operations. |
| 363 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer | 416 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer |
| 364 // sequence on failure. | 417 // sequence on failure. |
| 365 void andi(Register rd, Register rn, uint64_t imm) { | 418 void andi(Register rd, Register rn, uint64_t imm) { |
| 366 Operand imm_op; | 419 Operand imm_op; |
| 367 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 420 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 368 ASSERT(immok); | 421 ASSERT(immok); |
| 369 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); | 422 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); |
| 370 } | 423 } |
| 371 void orri(Register rd, Register rn, uint64_t imm) { | 424 void orri(Register rd, Register rn, uint64_t imm) { |
| 372 Operand imm_op; | 425 Operand imm_op; |
| 373 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 426 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 374 ASSERT(immok); | 427 ASSERT(immok); |
| 375 EmitLogicalImmOp(ORRI, rd, rn, imm_op, kDoubleWord); | 428 EmitLogicalImmOp(ORRI, rd, rn, imm_op, kDoubleWord); |
| 376 } | 429 } |
| 377 void eori(Register rd, Register rn, uint64_t imm) { | 430 void eori(Register rd, Register rn, uint64_t imm) { |
| 378 Operand imm_op; | 431 Operand imm_op; |
| 379 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 432 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 380 ASSERT(immok); | 433 ASSERT(immok); |
| 381 EmitLogicalImmOp(EORI, rd, rn, imm_op, kDoubleWord); | 434 EmitLogicalImmOp(EORI, rd, rn, imm_op, kDoubleWord); |
| 382 } | 435 } |
| 383 void andis(Register rd, Register rn, uint64_t imm) { | 436 void andis(Register rd, Register rn, uint64_t imm) { |
| 384 Operand imm_op; | 437 Operand imm_op; |
| 385 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 438 const bool immok = Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 386 ASSERT(immok); | 439 ASSERT(immok); |
| 387 EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kDoubleWord); | 440 EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kDoubleWord); |
| 388 } | 441 } |
| 389 | 442 |
| 390 // Logical (shifted) register operations. | 443 // Logical (shifted) register operations. |
| 391 void and_(Register rd, Register rn, Operand o) { | 444 void and_(Register rd, Register rn, Operand o) { |
| 392 EmitLogicalShiftOp(AND, rd, rn, o, kDoubleWord); | 445 EmitLogicalShiftOp(AND, rd, rn, o, kDoubleWord); |
| 393 } | 446 } |
| 394 void bic(Register rd, Register rn, Operand o) { | 447 void bic(Register rd, Register rn, Operand o) { |
| 395 EmitLogicalShiftOp(BIC, rd, rn, o, kDoubleWord); | 448 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); | 480 EmitMiscDP2Source(LSRV, rd, rn, rm, kDoubleWord); |
| 428 } | 481 } |
| 429 void asrv(Register rd, Register rn, Register rm) { | 482 void asrv(Register rd, Register rn, Register rm) { |
| 430 EmitMiscDP2Source(ASRV, rd, rn, rm, kDoubleWord); | 483 EmitMiscDP2Source(ASRV, rd, rn, rm, kDoubleWord); |
| 431 } | 484 } |
| 432 void madd(Register rd, Register rn, Register rm, Register ra) { | 485 void madd(Register rd, Register rn, Register rm, Register ra) { |
| 433 EmitMiscDP3Source(MADD, rd, rn, rm, ra, kDoubleWord); | 486 EmitMiscDP3Source(MADD, rd, rn, rm, ra, kDoubleWord); |
| 434 } | 487 } |
| 435 | 488 |
| 436 // Move wide immediate. | 489 // Move wide immediate. |
| 437 void movk(Register rd, int32_t imm, int32_t hw_idx) { | 490 void movk(Register rd, uint16_t imm, int hw_idx) { |
|
regis
2014/04/15 23:37:04
Changed your mind? :-)
| |
| 438 ASSERT(rd != SP); | 491 ASSERT(rd != SP); |
| 439 const Register crd = ConcreteRegister(rd); | 492 const Register crd = ConcreteRegister(rd); |
| 440 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); | 493 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); |
| 441 } | 494 } |
| 442 void movn(Register rd, int32_t imm, int32_t hw_idx) { | 495 void movn(Register rd, uint16_t imm, int hw_idx) { |
| 443 ASSERT(rd != SP); | 496 ASSERT(rd != SP); |
| 444 const Register crd = ConcreteRegister(rd); | 497 const Register crd = ConcreteRegister(rd); |
| 445 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); | 498 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); |
| 446 } | 499 } |
| 447 void movz(Register rd, int32_t imm, int32_t hw_idx) { | 500 void movz(Register rd, uint16_t imm, int hw_idx) { |
| 448 ASSERT(rd != SP); | 501 ASSERT(rd != SP); |
| 449 const Register crd = ConcreteRegister(rd); | 502 const Register crd = ConcreteRegister(rd); |
| 450 EmitMoveWideOp(MOVZ, crd, imm, hw_idx, kDoubleWord); | 503 EmitMoveWideOp(MOVZ, crd, imm, hw_idx, kDoubleWord); |
| 451 } | 504 } |
| 452 | 505 |
| 453 // Loads and Stores. | 506 // Loads and Stores. |
| 454 void ldr(Register rt, Address a) { | 507 void ldr(Register rt, Address a) { |
| 455 // If we are doing pre-/post-indexing, and the base and result registers | 508 if (a.type() == Address::PCOffset) { |
| 456 // are the same, then the result of the load will be clobbered by the | 509 EmitLoadRegLiteral(LDRpc, rt, a, kDoubleWord); |
| 457 // writeback, which is unlikely to be useful. | 510 } else { |
| 458 ASSERT(((a.type() != Address::PreIndex) && | 511 // If we are doing pre-/post-indexing, and the base and result registers |
| 459 (a.type() != Address::PostIndex)) || | 512 // are the same, then the result of the load will be clobbered by the |
| 460 (rt != a.base())); | 513 // writeback, which is unlikely to be useful. |
| 461 EmitLoadStoreReg(LDR, rt, a, kDoubleWord); | 514 ASSERT(((a.type() != Address::PreIndex) && |
| 515 (a.type() != Address::PostIndex)) || | |
| 516 (rt != a.base())); | |
| 517 EmitLoadStoreReg(LDR, rt, a, kDoubleWord); | |
| 518 } | |
| 462 } | 519 } |
| 463 void str(Register rt, Address a) { | 520 void str(Register rt, Address a) { |
| 464 EmitLoadStoreReg(STR, rt, a, kDoubleWord); | 521 EmitLoadStoreReg(STR, rt, a, kDoubleWord); |
| 465 } | 522 } |
| 466 | 523 |
| 467 // Comparison. | 524 // Comparison. |
| 468 // rn cmp o. | 525 // rn cmp o. |
| 469 void cmp(Register rn, Operand o) { | 526 void cmp(Register rn, Operand o) { |
| 470 subs(ZR, rn, o); | 527 subs(ZR, rn, o); |
| 471 } | 528 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 } | 563 } |
| 507 void neg(Register rd, Register rm) { | 564 void neg(Register rd, Register rm) { |
| 508 sub(rd, ZR, Operand(rm)); | 565 sub(rd, ZR, Operand(rm)); |
| 509 } | 566 } |
| 510 void negs(Register rd, Register rm) { | 567 void negs(Register rd, Register rm) { |
| 511 subs(rd, ZR, Operand(rm)); | 568 subs(rd, ZR, Operand(rm)); |
| 512 } | 569 } |
| 513 void mul(Register rd, Register rn, Register rm) { | 570 void mul(Register rd, Register rn, Register rm) { |
| 514 madd(rd, rn, rm, ZR); | 571 madd(rd, rn, rm, ZR); |
| 515 } | 572 } |
| 573 void Push(Register reg) { | |
| 574 str(reg, Address(SP, -1 * kWordSize, Address::PreIndex)); | |
| 575 } | |
| 576 void Pop(Register reg) { | |
| 577 ldr(reg, Address(SP, 1 * kWordSize, Address::PostIndex)); | |
| 578 } | |
| 579 | |
| 580 // Object pool, loading from pool, etc. | |
| 581 void LoadPoolPointer(Register pp) { | |
| 582 const intptr_t object_pool_pc_dist = | |
| 583 Instructions::HeaderSize() - Instructions::object_pool_offset() + | |
| 584 CodeSize(); | |
| 585 // PP <- Read(PC - object_pool_pc_dist). | |
| 586 ldr(pp, Address::PC(-object_pool_pc_dist)); | |
| 587 } | |
| 588 | |
| 589 enum Patchability { | |
| 590 kPatchable, | |
| 591 kNotPatchable, | |
| 592 }; | |
| 593 | |
| 594 void LoadWordFromPoolOffset(Register dst, Register pp, uint32_t offset); | |
| 595 intptr_t FindObject(const Object& obj, Patchability patchable); | |
| 596 intptr_t FindImmediate(int64_t imm); | |
| 597 bool CanLoadObjectFromPool(const Object& object); | |
| 598 bool CanLoadImmediateFromPool(int64_t imm, Register pp); | |
| 599 void LoadObject(Register dst, const Object& obj, Register pp); | |
| 600 void LoadImmediate(Register reg, int64_t imm, Register pp); | |
| 516 | 601 |
| 517 private: | 602 private: |
| 518 AssemblerBuffer buffer_; // Contains position independent code. | 603 AssemblerBuffer buffer_; // Contains position independent code. |
| 519 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. | 604 |
| 605 // Objects and patchable jump targets. | |
| 606 GrowableObjectArray& object_pool_; | |
| 607 | |
| 608 // Patchability of pool entries. | |
| 609 GrowableArray<Patchability> patchable_pool_entries_; | |
| 610 | |
| 611 // Pair type parameter for DirectChainedHashMap. | |
| 612 class ObjIndexPair { | |
| 613 public: | |
| 614 // TODO(zra): A WeakTable should be used here instead, but then it would | |
| 615 // also have to be possible to register and de-register WeakTables with the | |
| 616 // heap. Also, the Assembler would need to become a StackResource. | |
| 617 // Issue 13305. In the meantime... | |
| 618 // CAUTION: the RawObject* below is only safe because: | |
| 619 // The HashMap that will use this pair type will not contain any RawObject* | |
| 620 // keys that are not in the object_pool_ array. Since the keys will be | |
| 621 // visited by the GC when it visits the object_pool_, and since all objects | |
| 622 // in the object_pool_ are Old (and so will not be moved) the GC does not | |
| 623 // also need to visit the keys here in the HashMap. | |
| 624 | |
| 625 // Typedefs needed for the DirectChainedHashMap template. | |
| 626 typedef RawObject* Key; | |
| 627 typedef intptr_t Value; | |
| 628 typedef ObjIndexPair Pair; | |
| 629 | |
| 630 ObjIndexPair(Key key, Value value) : key_(key), value_(value) { } | |
| 631 | |
| 632 static Key KeyOf(Pair kv) { return kv.key_; } | |
| 633 | |
| 634 static Value ValueOf(Pair kv) { return kv.value_; } | |
| 635 | |
| 636 static intptr_t Hashcode(Key key) { | |
| 637 return reinterpret_cast<intptr_t>(key) >> kObjectAlignmentLog2; | |
| 638 } | |
| 639 | |
| 640 static inline bool IsKeyEqual(Pair kv, Key key) { | |
| 641 return kv.key_ == key; | |
| 642 } | |
| 643 | |
| 644 private: | |
| 645 Key key_; | |
| 646 Value value_; | |
| 647 }; | |
| 648 | |
| 649 // Hashmap for fast lookup in object pool. | |
| 650 DirectChainedHashMap<ObjIndexPair> object_pool_index_table_; | |
| 651 | |
| 520 int32_t prologue_offset_; | 652 int32_t prologue_offset_; |
| 521 | 653 |
| 522 bool use_far_branches_; | 654 bool use_far_branches_; |
| 523 | 655 |
| 524 class CodeComment : public ZoneAllocated { | 656 class CodeComment : public ZoneAllocated { |
| 525 public: | 657 public: |
| 526 CodeComment(intptr_t pc_offset, const String& comment) | 658 CodeComment(intptr_t pc_offset, const String& comment) |
| 527 : pc_offset_(pc_offset), comment_(comment) { } | 659 : pc_offset_(pc_offset), comment_(comment) { } |
| 528 | 660 |
| 529 intptr_t pc_offset() const { return pc_offset_; } | 661 intptr_t pc_offset() const { return pc_offset_; } |
| 530 const String& comment() const { return comment_; } | 662 const String& comment() const { return comment_; } |
| 531 | 663 |
| 532 private: | 664 private: |
| 533 intptr_t pc_offset_; | 665 intptr_t pc_offset_; |
| 534 const String& comment_; | 666 const String& comment_; |
| 535 | 667 |
| 536 DISALLOW_COPY_AND_ASSIGN(CodeComment); | 668 DISALLOW_COPY_AND_ASSIGN(CodeComment); |
| 537 }; | 669 }; |
| 538 | 670 |
| 539 GrowableArray<CodeComment*> comments_; | 671 GrowableArray<CodeComment*> comments_; |
| 540 | 672 |
| 541 bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op); | |
| 542 | |
| 543 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, | 673 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, |
| 544 Register rd, Register rn, Operand o) { | 674 Register rd, Register rn, Operand o) { |
| 545 ASSERT((rd != R31) && (rn != R31)); | 675 ASSERT((rd != R31) && (rn != R31)); |
| 546 const Register crd = ConcreteRegister(rd); | 676 const Register crd = ConcreteRegister(rd); |
| 547 const Register crn = ConcreteRegister(rn); | 677 const Register crn = ConcreteRegister(rn); |
| 548 if (o.type() == Operand::Immediate) { | 678 if (o.type() == Operand::Immediate) { |
| 549 ASSERT(rn != ZR); | 679 ASSERT(rn != ZR); |
| 550 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); | 680 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); |
| 551 } else if (o.type() == Operand::Shifted) { | 681 } else if (o.type() == Operand::Shifted) { |
| 552 ASSERT((rd != SP) && (rn != SP)); | 682 ASSERT((rd != SP) && (rn != SP)); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 673 label->LinkTo(position); | 803 label->LinkTo(position); |
| 674 } | 804 } |
| 675 } | 805 } |
| 676 | 806 |
| 677 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { | 807 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { |
| 678 const int32_t encoding = | 808 const int32_t encoding = |
| 679 op | (static_cast<int32_t>(rn) << kRnShift); | 809 op | (static_cast<int32_t>(rn) << kRnShift); |
| 680 Emit(encoding); | 810 Emit(encoding); |
| 681 } | 811 } |
| 682 | 812 |
| 683 void EmitMoveWideOp(MoveWideOp op, Register rd, int32_t imm, int32_t hw_idx, | 813 void EmitMoveWideOp(MoveWideOp op, Register rd, uint16_t imm, int hw_idx, |
| 684 OperandSize sz) { | 814 OperandSize sz) { |
| 685 ASSERT(Utils::IsUint(16, imm)); | |
| 686 ASSERT((hw_idx >= 0) && (hw_idx <= 3)); | 815 ASSERT((hw_idx >= 0) && (hw_idx <= 3)); |
| 687 ASSERT((sz == kDoubleWord) || (sz == kWord)); | 816 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 688 const int32_t size = (sz == kDoubleWord) ? B31 : 0; | 817 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 689 const int32_t encoding = | 818 const int32_t encoding = |
| 690 op | size | | 819 op | size | |
| 691 (static_cast<int32_t>(rd) << kRdShift) | | 820 (static_cast<int32_t>(rd) << kRdShift) | |
| 692 (hw_idx << kHWShift) | | 821 (static_cast<int32_t>(hw_idx) << kHWShift) | |
| 693 (imm << kImm16Shift); | 822 (static_cast<int32_t>(imm) << kImm16Shift); |
| 694 Emit(encoding); | 823 Emit(encoding); |
| 695 } | 824 } |
| 696 | 825 |
| 697 void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a, | 826 void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a, |
| 698 OperandSize sz) { | 827 OperandSize sz) { |
| 699 const int32_t size = Log2OperandSizeBytes(sz); | 828 const int32_t size = Log2OperandSizeBytes(sz); |
| 700 const int32_t encoding = | 829 const int32_t encoding = |
| 701 op | (size << kSzShift) | | 830 op | (size << kSzShift) | |
| 702 (static_cast<int32_t>(rt) << kRtShift) | | 831 (static_cast<int32_t>(rt) << kRtShift) | |
| 703 a.encoding(); | 832 a.encoding(); |
| 704 Emit(encoding); | 833 Emit(encoding); |
| 705 } | 834 } |
| 706 | 835 |
| 836 void EmitLoadRegLiteral(LoadRegLiteralOp op, Register rt, Address a, | |
| 837 OperandSize sz) { | |
| 838 ASSERT((sz == kDoubleWord) || (sz == kWord)); | |
| 839 const int32_t size = (sz == kDoubleWord) ? B30 : 0; | |
| 840 const int32_t encoding = | |
| 841 op | size | | |
| 842 (static_cast<int32_t>(rt) << kRtShift) | | |
| 843 a.encoding(); | |
| 844 Emit(encoding); | |
| 845 } | |
| 846 | |
| 707 void EmitPCRelOp(PCRelOp op, Register rd, int64_t imm) { | 847 void EmitPCRelOp(PCRelOp op, Register rd, int64_t imm) { |
| 708 ASSERT(Utils::IsInt(21, imm)); | 848 ASSERT(Utils::IsInt(21, imm)); |
| 709 ASSERT((rd != R31) && (rd != SP)); | 849 ASSERT((rd != R31) && (rd != SP)); |
| 710 const Register crd = ConcreteRegister(rd); | 850 const Register crd = ConcreteRegister(rd); |
| 711 const int32_t loimm = (imm & 0x3) << 29; | 851 const int32_t loimm = (imm & 0x3) << 29; |
| 712 const int32_t hiimm = ((imm >> 2) & kImm19Mask) << kImm19Shift; | 852 const int32_t hiimm = ((imm >> 2) & kImm19Mask) << kImm19Shift; |
| 713 const int32_t encoding = | 853 const int32_t encoding = |
| 714 op | loimm | hiimm | | 854 op | loimm | hiimm | |
| 715 (static_cast<int32_t>(crd) << kRdShift); | 855 (static_cast<int32_t>(crd) << kRdShift); |
| 716 Emit(encoding); | 856 Emit(encoding); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 750 Emit(encoding); | 890 Emit(encoding); |
| 751 } | 891 } |
| 752 | 892 |
| 753 DISALLOW_ALLOCATION(); | 893 DISALLOW_ALLOCATION(); |
| 754 DISALLOW_COPY_AND_ASSIGN(Assembler); | 894 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 755 }; | 895 }; |
| 756 | 896 |
| 757 } // namespace dart | 897 } // namespace dart |
| 758 | 898 |
| 759 #endif // VM_ASSEMBLER_ARM64_H_ | 899 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |