| 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 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 ~Assembler() { } | 271 ~Assembler() { } |
| 272 | 272 |
| 273 void PopRegister(Register r) { | 273 void PopRegister(Register r) { |
| 274 UNIMPLEMENTED(); | 274 UNIMPLEMENTED(); |
| 275 } | 275 } |
| 276 | 276 |
| 277 void Drop(intptr_t stack_elements) { | 277 void Drop(intptr_t stack_elements) { |
| 278 UNIMPLEMENTED(); | 278 UNIMPLEMENTED(); |
| 279 } | 279 } |
| 280 | 280 |
| 281 void Bind(Label* label) { | 281 void Bind(Label* label); |
| 282 UNIMPLEMENTED(); | |
| 283 } | |
| 284 | 282 |
| 285 // Misc. functionality | 283 // Misc. functionality |
| 286 intptr_t CodeSize() const { return buffer_.Size(); } | 284 intptr_t CodeSize() const { return buffer_.Size(); } |
| 287 intptr_t prologue_offset() const { return prologue_offset_; } | 285 intptr_t prologue_offset() const { return prologue_offset_; } |
| 288 | 286 |
| 289 // Count the fixups that produce a pointer offset, without processing | 287 // Count the fixups that produce a pointer offset, without processing |
| 290 // the fixups. On ARM64 there are no pointers in code. | 288 // the fixups. On ARM64 there are no pointers in code. |
| 291 intptr_t CountPointerOffsets() const { return 0; } | 289 intptr_t CountPointerOffsets() const { return 0; } |
| 292 | 290 |
| 293 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { | 291 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 void addw(Register rd, Register rn, Operand o) { | 347 void addw(Register rd, Register rn, Operand o) { |
| 350 AddSubHelper(kWord, false, false, rd, rn, o); | 348 AddSubHelper(kWord, false, false, rd, rn, o); |
| 351 } | 349 } |
| 352 void sub(Register rd, Register rn, Operand o) { | 350 void sub(Register rd, Register rn, Operand o) { |
| 353 AddSubHelper(kDoubleWord, false, true, rd, rn, o); | 351 AddSubHelper(kDoubleWord, false, true, rd, rn, o); |
| 354 } | 352 } |
| 355 void subs(Register rd, Register rn, Operand o) { | 353 void subs(Register rd, Register rn, Operand o) { |
| 356 AddSubHelper(kDoubleWord, true, true, rd, rn, o); | 354 AddSubHelper(kDoubleWord, true, true, rd, rn, o); |
| 357 } | 355 } |
| 358 | 356 |
| 357 // PC relative immediate add. imm is in bytes. |
| 358 void adr(Register rd, int64_t imm) { |
| 359 EmitPCRelOp(ADR, rd, imm); |
| 360 } |
| 361 |
| 359 // Logical immediate operations. | 362 // Logical immediate operations. |
| 360 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer | 363 // TODO(zra): Add macros that check IsImmLogical, and fall back on a longer |
| 361 // sequence on failure. | 364 // sequence on failure. |
| 362 void andi(Register rd, Register rn, uint64_t imm) { | 365 void andi(Register rd, Register rn, uint64_t imm) { |
| 363 Operand imm_op; | 366 Operand imm_op; |
| 364 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); | 367 const bool immok = IsImmLogical(imm, kXRegSizeInBits, &imm_op); |
| 365 ASSERT(immok); | 368 ASSERT(immok); |
| 366 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); | 369 EmitLogicalImmOp(ANDI, rd, rn, imm_op, kDoubleWord); |
| 367 } | 370 } |
| 368 void orri(Register rd, Register rn, uint64_t imm) { | 371 void orri(Register rd, Register rn, uint64_t imm) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 void eon(Register rd, Register rn, Operand o) { | 406 void eon(Register rd, Register rn, Operand o) { |
| 404 EmitLogicalShiftOp(EON, rd, rn, o, kDoubleWord); | 407 EmitLogicalShiftOp(EON, rd, rn, o, kDoubleWord); |
| 405 } | 408 } |
| 406 void ands(Register rd, Register rn, Operand o) { | 409 void ands(Register rd, Register rn, Operand o) { |
| 407 EmitLogicalShiftOp(ANDS, rd, rn, o, kDoubleWord); | 410 EmitLogicalShiftOp(ANDS, rd, rn, o, kDoubleWord); |
| 408 } | 411 } |
| 409 void bics(Register rd, Register rn, Operand o) { | 412 void bics(Register rd, Register rn, Operand o) { |
| 410 EmitLogicalShiftOp(BICS, rd, rn, o, kDoubleWord); | 413 EmitLogicalShiftOp(BICS, rd, rn, o, kDoubleWord); |
| 411 } | 414 } |
| 412 | 415 |
| 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 } | |
| 422 | |
| 423 // Move wide immediate. | 416 // Move wide immediate. |
| 424 void movk(Register rd, int32_t imm, int32_t hw_idx) { | 417 void movk(Register rd, int32_t imm, int32_t hw_idx) { |
| 425 ASSERT(rd != SP); | 418 ASSERT(rd != SP); |
| 426 const Register crd = ConcreteRegister(rd); | 419 const Register crd = ConcreteRegister(rd); |
| 427 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); | 420 EmitMoveWideOp(MOVK, crd, imm, hw_idx, kDoubleWord); |
| 428 } | 421 } |
| 429 void movn(Register rd, int32_t imm, int32_t hw_idx) { | 422 void movn(Register rd, int32_t imm, int32_t hw_idx) { |
| 430 ASSERT(rd != SP); | 423 ASSERT(rd != SP); |
| 431 const Register crd = ConcreteRegister(rd); | 424 const Register crd = ConcreteRegister(rd); |
| 432 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); | 425 EmitMoveWideOp(MOVN, crd, imm, hw_idx, kDoubleWord); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 444 // writeback, which is unlikely to be useful. | 437 // writeback, which is unlikely to be useful. |
| 445 ASSERT(((a.type() != Address::PreIndex) && | 438 ASSERT(((a.type() != Address::PreIndex) && |
| 446 (a.type() != Address::PostIndex)) || | 439 (a.type() != Address::PostIndex)) || |
| 447 (rt != a.base())); | 440 (rt != a.base())); |
| 448 EmitLoadStoreReg(LDR, rt, a, kDoubleWord); | 441 EmitLoadStoreReg(LDR, rt, a, kDoubleWord); |
| 449 } | 442 } |
| 450 void str(Register rt, Address a) { | 443 void str(Register rt, Address a) { |
| 451 EmitLoadStoreReg(STR, rt, a, kDoubleWord); | 444 EmitLoadStoreReg(STR, rt, a, kDoubleWord); |
| 452 } | 445 } |
| 453 | 446 |
| 454 // Function return. | 447 // Comparison. |
| 448 // rn cmp o. |
| 449 void cmp(Register rn, Operand o) { |
| 450 subs(ZR, rn, o); |
| 451 } |
| 452 // rn cmp -o. |
| 453 void cmn(Register rn, Operand o) { |
| 454 adds(ZR, rn, o); |
| 455 } |
| 456 |
| 457 // Conditional branch. |
| 458 void b(Label* label, Condition cond = AL) { |
| 459 EmitBranch(BCOND, cond, label); |
| 460 } |
| 461 |
| 462 // TODO(zra): branch and link with imm26 offset. |
| 463 // TODO(zra): cbz, cbnz. |
| 464 |
| 465 // Branch, link, return. |
| 466 void br(Register rn) { |
| 467 EmitUnconditionalBranchRegOp(BR, rn); |
| 468 } |
| 469 void blr(Register rn) { |
| 470 EmitUnconditionalBranchRegOp(BLR, rn); |
| 471 } |
| 455 void ret(Register rn = R30) { | 472 void ret(Register rn = R30) { |
| 456 EmitUnconditionalBranchRegOp(RET, rn); | 473 EmitUnconditionalBranchRegOp(RET, rn); |
| 457 } | 474 } |
| 458 | 475 |
| 459 private: | 476 private: |
| 460 AssemblerBuffer buffer_; // Contains position independent code. | 477 AssemblerBuffer buffer_; // Contains position independent code. |
| 461 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. | 478 GrowableObjectArray& object_pool_; // Objects and patchable jump targets. |
| 462 int32_t prologue_offset_; | 479 int32_t prologue_offset_; |
| 463 | 480 |
| 464 bool use_far_branches_; | 481 bool use_far_branches_; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 481 GrowableArray<CodeComment*> comments_; | 498 GrowableArray<CodeComment*> comments_; |
| 482 | 499 |
| 483 bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op); | 500 bool IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op); |
| 484 | 501 |
| 485 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, | 502 void AddSubHelper(OperandSize os, bool set_flags, bool subtract, |
| 486 Register rd, Register rn, Operand o) { | 503 Register rd, Register rn, Operand o) { |
| 487 ASSERT((rd != R31) && (rn != R31)); | 504 ASSERT((rd != R31) && (rn != R31)); |
| 488 const Register crd = ConcreteRegister(rd); | 505 const Register crd = ConcreteRegister(rd); |
| 489 const Register crn = ConcreteRegister(rn); | 506 const Register crn = ConcreteRegister(rn); |
| 490 if (o.type() == Operand::Immediate) { | 507 if (o.type() == Operand::Immediate) { |
| 491 ASSERT((rd != ZR) && (rn != ZR)); | 508 ASSERT(rn != ZR); |
| 492 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); | 509 EmitAddSubImmOp(subtract ? SUBI : ADDI, crd, crn, o, os, set_flags); |
| 493 } else if (o.type() == Operand::Shifted) { | 510 } else if (o.type() == Operand::Shifted) { |
| 494 ASSERT((rd != SP) && (rn != SP)); | 511 ASSERT((rd != SP) && (rn != SP)); |
| 495 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); | 512 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); |
| 496 } else { | 513 } else { |
| 497 ASSERT(o.type() == Operand::Extended); | 514 ASSERT(o.type() == Operand::Extended); |
| 498 ASSERT((rd != SP) && (rn != ZR)); | 515 ASSERT((rd != SP) && (rn != ZR)); |
| 499 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); | 516 EmitAddSubShiftExtOp(subtract ? SUB : ADD, crd, crn, o, os, set_flags); |
| 500 } | 517 } |
| 501 } | 518 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 const int32_t size = (sz == kDoubleWord) ? B31 : 0; | 573 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 557 const int32_t s = set_flags ? B29 : 0; | 574 const int32_t s = set_flags ? B29 : 0; |
| 558 const int32_t encoding = | 575 const int32_t encoding = |
| 559 op | size | s | | 576 op | size | s | |
| 560 (static_cast<int32_t>(rd) << kRdShift) | | 577 (static_cast<int32_t>(rd) << kRdShift) | |
| 561 (static_cast<int32_t>(rn) << kRnShift) | | 578 (static_cast<int32_t>(rn) << kRnShift) | |
| 562 o.encoding(); | 579 o.encoding(); |
| 563 Emit(encoding); | 580 Emit(encoding); |
| 564 } | 581 } |
| 565 | 582 |
| 583 int32_t EncodeImm19BranchOffset(int64_t imm, int32_t instr) { |
| 584 const int32_t imm32 = static_cast<int32_t>(imm); |
| 585 const int32_t off = (((imm32 >> 2) & kImm19Mask) << kImm19Shift); |
| 586 return (instr & ~(kImm19Mask << kImm19Shift)) | off; |
| 587 } |
| 588 |
| 589 int64_t DecodeImm19BranchOffset(int32_t instr) { |
| 590 const int32_t off = (((instr >> kImm19Shift) & kImm19Shift) << 13) >> 13; |
| 591 return static_cast<int64_t>(off); |
| 592 } |
| 593 |
| 594 void EmitCompareAndBranch(CompareAndBranchOp op, Register rt, int64_t imm, |
| 595 OperandSize sz) { |
| 596 ASSERT((sz == kDoubleWord) || (sz == kWord)); |
| 597 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); |
| 598 const int32_t size = (sz == kDoubleWord) ? B31 : 0; |
| 599 const int32_t encoded_offset = EncodeImm19BranchOffset(imm, 0); |
| 600 const int32_t encoding = |
| 601 op | size | |
| 602 (static_cast<int32_t>(rt) << kRtShift) | |
| 603 encoded_offset; |
| 604 Emit(encoding); |
| 605 } |
| 606 |
| 607 void EmitConditionalBranch(ConditionalBranchOp op, Condition cond, |
| 608 int64_t imm) { |
| 609 ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0)); |
| 610 const int32_t encoding = |
| 611 op | |
| 612 (static_cast<int32_t>(cond) << kCondShift) | |
| 613 (((imm >> 2) & kImm19Mask) << kImm19Shift); |
| 614 Emit(encoding); |
| 615 } |
| 616 |
| 617 bool CanEncodeImm19BranchOffset(int64_t offset) { |
| 618 ASSERT(Utils::IsAligned(offset, 4)); |
| 619 return Utils::IsInt(19, offset); |
| 620 } |
| 621 |
| 622 // TODO(zra): Implement far branches. Requires loading large immediates. |
| 623 void EmitBranch(ConditionalBranchOp op, Condition cond, Label* label) { |
| 624 if (label->IsBound()) { |
| 625 const int64_t dest = label->Position() - buffer_.Size(); |
| 626 ASSERT(CanEncodeImm19BranchOffset(dest)); |
| 627 EmitConditionalBranch(op, cond, dest); |
| 628 } else { |
| 629 const int64_t position = buffer_.Size(); |
| 630 ASSERT(CanEncodeImm19BranchOffset(position)); |
| 631 EmitConditionalBranch(op, cond, label->position_); |
| 632 label->LinkTo(position); |
| 633 } |
| 634 } |
| 635 |
| 566 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { | 636 void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) { |
| 567 const int32_t encoding = | 637 const int32_t encoding = |
| 568 op | (static_cast<int32_t>(rn) << kRnShift); | 638 op | (static_cast<int32_t>(rn) << kRnShift); |
| 569 Emit(encoding); | 639 Emit(encoding); |
| 570 } | 640 } |
| 571 | 641 |
| 572 void EmitMoveWideOp(MoveWideOp op, Register rd, int32_t imm, int32_t hw_idx, | 642 void EmitMoveWideOp(MoveWideOp op, Register rd, int32_t imm, int32_t hw_idx, |
| 573 OperandSize sz) { | 643 OperandSize sz) { |
| 574 ASSERT(Utils::IsUint(16, imm)); | 644 ASSERT(Utils::IsUint(16, imm)); |
| 575 ASSERT((hw_idx >= 0) && (hw_idx <= 3)); | 645 ASSERT((hw_idx >= 0) && (hw_idx <= 3)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 586 void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a, | 656 void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a, |
| 587 OperandSize sz) { | 657 OperandSize sz) { |
| 588 const int32_t size = Log2OperandSizeBytes(sz); | 658 const int32_t size = Log2OperandSizeBytes(sz); |
| 589 const int32_t encoding = | 659 const int32_t encoding = |
| 590 op | (size << kSzShift) | | 660 op | (size << kSzShift) | |
| 591 (static_cast<int32_t>(rt) << kRtShift) | | 661 (static_cast<int32_t>(rt) << kRtShift) | |
| 592 a.encoding(); | 662 a.encoding(); |
| 593 Emit(encoding); | 663 Emit(encoding); |
| 594 } | 664 } |
| 595 | 665 |
| 666 void EmitPCRelOp(PCRelOp op, Register rd, int64_t imm) { |
| 667 ASSERT(Utils::IsInt(21, imm)); |
| 668 ASSERT((rd != R31) && (rd != SP)); |
| 669 const Register crd = ConcreteRegister(rd); |
| 670 const int32_t loimm = (imm & 0x3) << 29; |
| 671 const int32_t hiimm = ((imm >> 2) & kImm19Mask) << kImm19Shift; |
| 672 const int32_t encoding = |
| 673 op | loimm | hiimm | |
| 674 (static_cast<int32_t>(crd) << kRdShift); |
| 675 Emit(encoding); |
| 676 } |
| 677 |
| 596 DISALLOW_ALLOCATION(); | 678 DISALLOW_ALLOCATION(); |
| 597 DISALLOW_COPY_AND_ASSIGN(Assembler); | 679 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 598 }; | 680 }; |
| 599 | 681 |
| 600 } // namespace dart | 682 } // namespace dart |
| 601 | 683 |
| 602 #endif // VM_ASSEMBLER_ARM64_H_ | 684 #endif // VM_ASSEMBLER_ARM64_H_ |
| OLD | NEW |