| 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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 | 169 |
| 170 class Operand : public ValueObject { | 170 class Operand : public ValueObject { |
| 171 public: | 171 public: |
| 172 // Data-processing operand - Uninitialized. | 172 // Data-processing operand - Uninitialized. |
| 173 Operand() : encoding_(-1), type_(Unknown) { } | 173 Operand() : encoding_(-1), type_(Unknown) { } |
| 174 | 174 |
| 175 // Data-processing operands - Copy constructor. | 175 // Data-processing operands - Copy constructor. |
| 176 Operand(const Operand& other) | 176 Operand(const Operand& other) |
| 177 : ValueObject(), encoding_(other.encoding_), type_(other.type_) { } | 177 : ValueObject(), encoding_(other.encoding_), type_(other.type_) { } |
| 178 | 178 |
| 179 Operand& operator=(const Operand& other) { |
| 180 type_ = other.type_; |
| 181 encoding_ = other.encoding_; |
| 182 return *this; |
| 183 } |
| 184 |
| 179 explicit Operand(Register rm) { | 185 explicit Operand(Register rm) { |
| 180 ASSERT((rm != R31) && (rm != SP)); | 186 ASSERT((rm != R31) && (rm != SP)); |
| 181 const Register crm = ConcreteRegister(rm); | 187 const Register crm = ConcreteRegister(rm); |
| 182 encoding_ = (static_cast<int32_t>(crm) << kRmShift); | 188 encoding_ = (static_cast<int32_t>(crm) << kRmShift); |
| 183 type_ = Shifted; | 189 type_ = Shifted; |
| 184 } | 190 } |
| 185 | 191 |
| 186 Operand(Register rm, Shift shift, int32_t imm) { | 192 Operand(Register rm, Shift shift, int32_t imm) { |
| 187 ASSERT(Utils::IsUint(6, imm)); | 193 ASSERT(Utils::IsUint(6, imm)); |
| 188 ASSERT((rm != R31) && (rm != SP)); | 194 ASSERT((rm != R31) && (rm != SP)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 210 if (Utils::IsUint(12, imm)) { | 216 if (Utils::IsUint(12, imm)) { |
| 211 encoding_ = imm << kImm12Shift; | 217 encoding_ = imm << kImm12Shift; |
| 212 } else { | 218 } else { |
| 213 // imm only has bits in [12, 24) set. | 219 // imm only has bits in [12, 24) set. |
| 214 ASSERT(((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12))); | 220 ASSERT(((imm & 0xfff) == 0) && (Utils::IsUint(12, imm >> 12))); |
| 215 encoding_ = B22 | ((imm >> 12) << kImm12Shift); | 221 encoding_ = B22 | ((imm >> 12) << kImm12Shift); |
| 216 } | 222 } |
| 217 type_ = Immediate; | 223 type_ = Immediate; |
| 218 } | 224 } |
| 219 | 225 |
| 220 // TODO(zra): Add bitfield immediate operand | 226 // Encodes the value of an immediate for a logical operation. |
| 221 // Operand(int32_t n, int32_t imms, int32_t immr); | 227 // 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 |
| 229 // imm_r. |
| 230 Operand(uint8_t n, int8_t imm_s, int8_t imm_r) { |
| 231 ASSERT((n == 1) || (n == 0)); |
| 232 ASSERT(Utils::IsUint(6, imm_s) && Utils::IsUint(6, imm_r)); |
| 233 type_ = BitfieldImm; |
| 234 encoding_ = |
| 235 (static_cast<int32_t>(n) << kNShift) | |
| 236 (static_cast<int32_t>(imm_s) << kImmSShift) | |
| 237 (static_cast<int32_t>(imm_r) << kImmRShift); |
| 238 } |
| 222 | 239 |
| 223 enum OperandType { | 240 enum OperandType { |
| 224 Shifted, | 241 Shifted, |
| 225 Extended, | 242 Extended, |
| 226 Immediate, | 243 Immediate, |
| 227 BitfieldImm, | 244 BitfieldImm, |
| 228 Unknown, | 245 Unknown, |
| 229 }; | 246 }; |
| 230 | 247 |
| 231 private: | 248 private: |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 | 336 |
| 320 // On some other platforms, we draw a distinction between safe and unsafe | 337 // On some other platforms, we draw a distinction between safe and unsafe |
| 321 // smis. | 338 // smis. |
| 322 static bool IsSafe(const Object& object) { return true; } | 339 static bool IsSafe(const Object& object) { return true; } |
| 323 static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } | 340 static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } |
| 324 | 341 |
| 325 // Addition and subtraction. | 342 // Addition and subtraction. |
| 326 void add(Register rd, Register rn, Operand o) { | 343 void add(Register rd, Register rn, Operand o) { |
| 327 AddSubHelper(kDoubleWord, false, false, rd, rn, o); | 344 AddSubHelper(kDoubleWord, false, false, rd, rn, o); |
| 328 } | 345 } |
| 346 void adds(Register rd, Register rn, Operand o) { |
| 347 AddSubHelper(kDoubleWord, true, false, rd, rn, o); |
| 348 } |
| 329 void addw(Register rd, Register rn, Operand o) { | 349 void addw(Register rd, Register rn, Operand o) { |
| 330 AddSubHelper(kWord, false, false, rd, rn, o); | 350 AddSubHelper(kWord, false, false, rd, rn, o); |
| 331 } | 351 } |
| 332 void sub(Register rd, Register rn, Operand o) { | 352 void sub(Register rd, Register rn, Operand o) { |
| 333 AddSubHelper(kDoubleWord, false, true, rd, rn, o); | 353 AddSubHelper(kDoubleWord, false, true, rd, rn, o); |
| 334 } | 354 } |
| 355 void subs(Register rd, Register rn, Operand o) { |
| 356 AddSubHelper(kDoubleWord, true, true, rd, rn, o); |
| 357 } |
| 358 |
| 359 // Logical immediate operations. |
| 360 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer |
| 361 // sequence on failure. |
| 362 void andi(Register rd, Register rn, uint64_t imm) { |
| 363 Operand imm_op; |
| 364 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 365 ASSERT(immok); |
| 366 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); |
| 367 } |
| 368 void orri(Register rd, Register rn, uint64_t imm) { |
| 369 Operand imm_op; |
| 370 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 371 ASSERT(immok); |
| 372 EmitLogicalImmOp(ORRI, rd, rn, imm_op, kDoubleWord); |
| 373 } |
| 374 void eori(Register rd, Register rn, uint64_t imm) { |
| 375 Operand imm_op; |
| 376 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 377 ASSERT(immok); |
| 378 EmitLogicalImmOp(EORI, rd, rn, imm_op, kDoubleWord); |
| 379 } |
| 380 void andis(Register rd, Register rn, uint64_t imm) { |
| 381 Operand imm_op; |
| 382 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 383 ASSERT(immok); |
| 384 EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kDoubleWord); |
| 385 } |
| 386 |
| 387 // Logical (shifted) register operations. |
| 388 void and_(Register rd, Register rn, Operand o) { |
| 389 EmitLogicalShiftOp(AND, rd, rn, o, kDoubleWord); |
| 390 } |
| 391 void bic(Register rd, Register rn, Operand o) { |
| 392 EmitLogicalShiftOp(BIC, rd, rn, o, kDoubleWord); |
| 393 } |
| 394 void orr(Register rd, Register rn, Operand o) { |
| 395 EmitLogicalShiftOp(ORR, rd, rn, o, kDoubleWord); |
| 396 } |
| 397 void orn(Register rd, Register rn, Operand o) { |
| 398 EmitLogicalShiftOp(ORN, rd, rn, o, kDoubleWord); |
| 399 } |
| 400 void eor(Register rd, Register rn, Operand o) { |
| 401 EmitLogicalShiftOp(EOR, rd, rn, o, kDoubleWord); |
| 402 } |
| 403 void eon(Register rd, Register rn, Operand o) { |
| 404 EmitLogicalShiftOp(EON, rd, rn, o, kDoubleWord); |
| 405 } |
| 406 void ands(Register rd, Register rn, Operand o) { |
| 407 EmitLogicalShiftOp(ANDS, rd, rn, o, kDoubleWord); |
| 408 } |
| 409 void bics(Register rd, Register rn, Operand o) { |
| 410 EmitLogicalShiftOp(BICS, rd, rn, o, kDoubleWord); |
| 411 } |
| 412 |
| 413 // Comparison. |
| 414 // rn cmp o. |
| 415 void cmp(Register rn, Operand o) { |
| 416 subs(ZR, rn, o); |
| 417 } |
| 418 // rn cmp -o. |
| 419 void cmn(Register rn, Operand o) { |
| 420 adds(ZR, rn, o); |
| 421 } |
| 335 | 422 |
| 336 // Move wide immediate. | 423 // Move wide immediate. |
| 337 void movk(Register rd, int32_t imm, int32_t hw_idx) { | 424 void movk(Register rd, int32_t imm, int32_t hw_idx) { |
| 338 ASSERT(rd != SP); | 425 ASSERT(rd != SP); |
| 339 const Register crd = ConcreteRegister(rd); | 426 const Register crd = ConcreteRegister(rd); |
| 340 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); | 427 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); |
| 341 } | 428 } |
| 342 void movn(Register rd, int32_t imm, int32_t hw_idx) { | 429 void movn(Register rd, int32_t imm, int32_t hw_idx) { |
| 343 ASSERT(rd != SP); | 430 ASSERT(rd != SP); |
| 344 const Register crd = ConcreteRegister(rd); | 431 const Register crd = ConcreteRegister(rd); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 | 473 |
| 387 private: | 474 private: |
| 388 intptr_t pc_offset_; | 475 intptr_t pc_offset_; |
| 389 const String& comment_; | 476 const String& comment_; |
| 390 | 477 |
| 391 DISALLOW_COPY_AND_ASSIGN(CodeComment); | 478 DISALLOW_COPY_AND_ASSIGN(CodeComment); |
| 392 }; | 479 }; |
| 393 | 480 |
| 394 GrowableArray<CodeComment*> comments_; | 481 GrowableArray<CodeComment*> comments_; |
| 395 | 482 |
| 483 bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op); |
| 484 |
| 396 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, | 485 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, |
| 397 Register rd, Register rn, Operand o) { | 486 Register rd, Register rn, Operand o) { |
| 398 ASSERT((rd != R31) && (rn != R31)); | 487 ASSERT((rd != R31) && (rn != R31)); |
| 399 const Register crd = ConcreteRegister(rd); | 488 const Register crd = ConcreteRegister(rd); |
| 400 const Register crn = ConcreteRegister(rn); | 489 const Register crn = ConcreteRegister(rn); |
| 401 if (o.type() == Operand::Immediate) { | 490 if (o.type() == Operand::Immediate) { |
| 402 ASSERT((rd != ZR) && (rn != ZR)); | 491 ASSERT((rd != ZR) && (rn != ZR)); |
| 403 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); | 492 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); |
| 404 } else if (o.type() == Operand::Shifted) { | 493 } else if (o.type() == Operand::Shifted) { |
| 405 ASSERT((rd != SP) && (rn != SP)); | 494 ASSERT((rd != SP) && (rn != SP)); |
| 406 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); | 495 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); |
| 407 } else { | 496 } else { |
| 408 ASSERT(o.type() == Operand::Extended); | 497 ASSERT(o.type() == Operand::Extended); |
| 409 ASSERT((rd != SP) && (rn != ZR)); | 498 ASSERT((rd != SP) && (rn != ZR)); |
| 410 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); | 499 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); |
| 411 } | 500 } |
| 412 } | 501 } |
| 413 | 502 |
| 414 void EmitAddSubImmOp(AddSubImmOp op, Register rd, Register rn, | 503 void EmitAddSubImmOp(AddSubImmOp op, Register rd, Register rn, |
| 415 Operand o, OperandSize os, bool set_flags) { | 504 Operand o, OperandSize sz, bool set_flags) { |
| 416 ASSERT((os == kDoubleWord) || (os == kWord)); | 505 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 417 const int32_t size = (os == kDoubleWord) ? B31 : 0; | 506 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 418 const int32_t s = set_flags ? B29 : 0; | 507 const int32_t s = set_flags ? B29 : 0; |
| 419 const int32_t encoding = | 508 const int32_t encoding = |
| 420 op | size | s | | 509 op | size | s | |
| 421 (static_cast<int32_t>(rd) << kRdShift) | | 510 (static_cast<int32_t>(rd) << kRdShift) | |
| 422 (static_cast<int32_t>(rn) << kRnShift) | | 511 (static_cast<int32_t>(rn) << kRnShift) | |
| 423 o.encoding(); | 512 o.encoding(); |
| 424 Emit(encoding); | 513 Emit(encoding); |
| 425 } | 514 } |
| 426 | 515 |
| 516 void EmitLogicalImmOp(LogicalImmOp op, Register rd, Register rn, |
| 517 Operand o, OperandSize sz) { |
| 518 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 519 ASSERT((rd != R31) && (rn != R31)); |
| 520 ASSERT(rn != SP); |
| 521 ASSERT((op == ANDIS) || (rd != ZR)); // op != ANDIS => rd != ZR. |
| 522 ASSERT((op != ANDIS) || (rd != SP)); // op == ANDIS => rd != SP. |
| 523 ASSERT(o.type() == Operand::BitfieldImm); |
| 524 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 525 const Register crd = ConcreteRegister(rd); |
| 526 const Register crn = ConcreteRegister(rn); |
| 527 const int32_t encoding = |
| 528 op | size | |
| 529 (static_cast<int32_t>(crd) << kRdShift) | |
| 530 (static_cast<int32_t>(crn) << kRnShift) | |
| 531 o.encoding(); |
| 532 Emit(encoding); |
| 533 } |
| 534 |
| 535 void EmitLogicalShiftOp(LogicalShiftOp op, |
| 536 Register rd, Register rn, Operand o, OperandSize sz) { |
| 537 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 538 ASSERT((rd != R31) && (rn != R31)); |
| 539 ASSERT((rd != SP) && (rn != SP)); |
| 540 ASSERT(o.type() == Operand::Shifted); |
| 541 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 542 const Register crd = ConcreteRegister(rd); |
| 543 const Register crn = ConcreteRegister(rn); |
| 544 const int32_t encoding = |
| 545 op | size | |
| 546 (static_cast<int32_t>(crd) << kRdShift) | |
| 547 (static_cast<int32_t>(crn) << kRnShift) | |
| 548 o.encoding(); |
| 549 Emit(encoding); |
| 550 } |
| 551 |
| 427 void EmitAddSubShiftExtOp(AddSubShiftExtOp op, | 552 void EmitAddSubShiftExtOp(AddSubShiftExtOp op, |
| 428 Register rd, Register rn, Operand o, | 553 Register rd, Register rn, Operand o, |
| 429 OperandSize sz, bool set_flags) { | 554 OperandSize sz, bool set_flags) { |
| 430 ASSERT((sz == kDoubleWord) || (sz == kWord)); | 555 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 431 const int32_t size = (sz == kDoubleWord) ? B31 : 0; | 556 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 432 const int32_t s = set_flags ? B29 : 0; | 557 const int32_t s = set_flags ? B29 : 0; |
| 433 const int32_t encoding = | 558 const int32_t encoding = |
| 434 op | size | s | | 559 op | size | s | |
| 435 (static_cast<int32_t>(rd) << kRdShift) | | 560 (static_cast<int32_t>(rd) << kRdShift) | |
| 436 (static_cast<int32_t>(rn) << kRnShift) | | 561 (static_cast<int32_t>(rn) << kRnShift) | |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 Emit(encoding); | 593 Emit(encoding); |
| 469 } | 594 } |
| 470 | 595 |
| 471 DISALLOW_ALLOCATION(); | 596 DISALLOW_ALLOCATION(); |
| 472 DISALLOW_COPY_AND_ASSIGN(Assembler); | 597 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 473 }; | 598 }; |
| 474 | 599 |
| 475 } // namespace dart | 600 } // namespace dart |
| 476 | 601 |
| 477 #endif // VM_ASSEMBLER_ARM64_H_ | 602 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |