| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
| 6 | 6 |
| 7 #include "src/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
| 8 #include "src/assembler.h" | 8 #include "src/assembler.h" |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/base/division-by-constant.h" | 10 #include "src/base/division-by-constant.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 | 124 |
| 125 unsigned n, imm_s, imm_r; | 125 unsigned n, imm_s, imm_r; |
| 126 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) { | 126 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) { |
| 127 // Immediate can be encoded in the instruction. | 127 // Immediate can be encoded in the instruction. |
| 128 LogicalImmediate(rd, rn, n, imm_s, imm_r, op); | 128 LogicalImmediate(rd, rn, n, imm_s, imm_r, op); |
| 129 } else { | 129 } else { |
| 130 // Immediate can't be encoded: synthesize using move immediate. | 130 // Immediate can't be encoded: synthesize using move immediate. |
| 131 Register temp = temps.AcquireSameSizeAs(rn); | 131 Register temp = temps.AcquireSameSizeAs(rn); |
| 132 Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate); | 132 |
| 133 // If the left-hand input is the stack pointer, we can't pre-shift the |
| 134 // immediate, as the encoding won't allow the subsequent post shift. |
| 135 PreShiftImmMode mode = rn.Is(csp) ? kNoShift : kAnyShift; |
| 136 Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate, mode); |
| 137 |
| 133 if (rd.Is(csp)) { | 138 if (rd.Is(csp)) { |
| 134 // If rd is the stack pointer we cannot use it as the destination | 139 // If rd is the stack pointer we cannot use it as the destination |
| 135 // register so we use the temp register as an intermediate again. | 140 // register so we use the temp register as an intermediate again. |
| 136 Logical(temp, rn, imm_operand, op); | 141 Logical(temp, rn, imm_operand, op); |
| 137 Mov(csp, temp); | 142 Mov(csp, temp); |
| 138 AssertStackConsistency(); | 143 AssertStackConsistency(); |
| 139 } else { | 144 } else { |
| 140 Logical(rd, rn, imm_operand, op); | 145 Logical(rd, rn, imm_operand, op); |
| 141 } | 146 } |
| 142 } | 147 } |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask)); | 600 movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask)); |
| 596 return true; | 601 return true; |
| 597 } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) { | 602 } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) { |
| 598 // Immediate can be represented in a logical orr instruction. | 603 // Immediate can be represented in a logical orr instruction. |
| 599 LogicalImmediate(dst, AppropriateZeroRegFor(dst), n, imm_s, imm_r, ORR); | 604 LogicalImmediate(dst, AppropriateZeroRegFor(dst), n, imm_s, imm_r, ORR); |
| 600 return true; | 605 return true; |
| 601 } | 606 } |
| 602 return false; | 607 return false; |
| 603 } | 608 } |
| 604 | 609 |
| 605 | |
| 606 Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst, | 610 Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst, |
| 607 int64_t imm) { | 611 int64_t imm, |
| 612 PreShiftImmMode mode) { |
| 608 int reg_size = dst.SizeInBits(); | 613 int reg_size = dst.SizeInBits(); |
| 609 | 614 |
| 610 // Encode the immediate in a single move instruction, if possible. | 615 // Encode the immediate in a single move instruction, if possible. |
| 611 if (TryOneInstrMoveImmediate(dst, imm)) { | 616 if (TryOneInstrMoveImmediate(dst, imm)) { |
| 612 // The move was successful; nothing to do here. | 617 // The move was successful; nothing to do here. |
| 613 } else { | 618 } else { |
| 614 // Pre-shift the immediate to the least-significant bits of the register. | 619 // Pre-shift the immediate to the least-significant bits of the register. |
| 615 int shift_low = CountTrailingZeros(imm, reg_size); | 620 int shift_low = CountTrailingZeros(imm, reg_size); |
| 621 if (mode == kLimitShiftForSP) { |
| 622 // When applied to the stack pointer, the subsequent arithmetic operation |
| 623 // can use the extend form to shift left by a maximum of four bits. Right |
| 624 // shifts are not allowed, so we filter them out later before the new |
| 625 // immediate is tested. |
| 626 shift_low = std::min(shift_low, 4); |
| 627 } |
| 616 int64_t imm_low = imm >> shift_low; | 628 int64_t imm_low = imm >> shift_low; |
| 617 | 629 |
| 618 // Pre-shift the immediate to the most-significant bits of the register. We | 630 // Pre-shift the immediate to the most-significant bits of the register. We |
| 619 // insert set bits in the least-significant bits, as this creates a | 631 // insert set bits in the least-significant bits, as this creates a |
| 620 // different immediate that may be encodable using movn or orr-immediate. | 632 // different immediate that may be encodable using movn or orr-immediate. |
| 621 // If this new immediate is encodable, the set bits will be eliminated by | 633 // If this new immediate is encodable, the set bits will be eliminated by |
| 622 // the post shift on the following instruction. | 634 // the post shift on the following instruction. |
| 623 int shift_high = CountLeadingZeros(imm, reg_size); | 635 int shift_high = CountLeadingZeros(imm, reg_size); |
| 624 int64_t imm_high = (imm << shift_high) | ((1 << shift_high) - 1); | 636 int64_t imm_high = (imm << shift_high) | ((1 << shift_high) - 1); |
| 625 | 637 |
| 626 if (TryOneInstrMoveImmediate(dst, imm_low)) { | 638 if ((mode != kNoShift) && TryOneInstrMoveImmediate(dst, imm_low)) { |
| 627 // The new immediate has been moved into the destination's low bits: | 639 // The new immediate has been moved into the destination's low bits: |
| 628 // return a new leftward-shifting operand. | 640 // return a new leftward-shifting operand. |
| 629 return Operand(dst, LSL, shift_low); | 641 return Operand(dst, LSL, shift_low); |
| 630 } else if (TryOneInstrMoveImmediate(dst, imm_high)) { | 642 } else if ((mode == kAnyShift) && TryOneInstrMoveImmediate(dst, imm_high)) { |
| 631 // The new immediate has been moved into the destination's high bits: | 643 // The new immediate has been moved into the destination's high bits: |
| 632 // return a new rightward-shifting operand. | 644 // return a new rightward-shifting operand. |
| 633 return Operand(dst, LSR, shift_high); | 645 return Operand(dst, LSR, shift_high); |
| 634 } else { | 646 } else { |
| 635 // Use the generic move operation to set up the immediate. | 647 // Use the generic move operation to set up the immediate. |
| 636 Mov(dst, imm); | 648 Mov(dst, imm); |
| 637 } | 649 } |
| 638 } | 650 } |
| 639 return Operand(dst); | 651 return Operand(dst); |
| 640 } | 652 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 656 Register temp = temps.AcquireX(); | 668 Register temp = temps.AcquireX(); |
| 657 Ldr(temp, operand.immediate()); | 669 Ldr(temp, operand.immediate()); |
| 658 AddSubMacro(rd, rn, temp, S, op); | 670 AddSubMacro(rd, rn, temp, S, op); |
| 659 } else if ((operand.IsImmediate() && | 671 } else if ((operand.IsImmediate() && |
| 660 !IsImmAddSub(operand.ImmediateValue())) || | 672 !IsImmAddSub(operand.ImmediateValue())) || |
| 661 (rn.IsZero() && !operand.IsShiftedRegister()) || | 673 (rn.IsZero() && !operand.IsShiftedRegister()) || |
| 662 (operand.IsShiftedRegister() && (operand.shift() == ROR))) { | 674 (operand.IsShiftedRegister() && (operand.shift() == ROR))) { |
| 663 UseScratchRegisterScope temps(this); | 675 UseScratchRegisterScope temps(this); |
| 664 Register temp = temps.AcquireSameSizeAs(rn); | 676 Register temp = temps.AcquireSameSizeAs(rn); |
| 665 if (operand.IsImmediate()) { | 677 if (operand.IsImmediate()) { |
| 678 PreShiftImmMode mode = kAnyShift; |
| 679 |
| 680 // If the destination or source register is the stack pointer, we can |
| 681 // only pre-shift the immediate right by values supported in the add/sub |
| 682 // extend encoding. |
| 683 if (rd.Is(csp)) { |
| 684 // If the destination is SP and flags will be set, we can't pre-shift |
| 685 // the immediate at all. |
| 686 mode = (S == SetFlags) ? kNoShift : kLimitShiftForSP; |
| 687 } else if (rn.Is(csp)) { |
| 688 mode = kLimitShiftForSP; |
| 689 } |
| 690 |
| 666 Operand imm_operand = | 691 Operand imm_operand = |
| 667 MoveImmediateForShiftedOp(temp, operand.ImmediateValue()); | 692 MoveImmediateForShiftedOp(temp, operand.ImmediateValue(), mode); |
| 668 AddSub(rd, rn, imm_operand, S, op); | 693 AddSub(rd, rn, imm_operand, S, op); |
| 669 } else { | 694 } else { |
| 670 Mov(temp, operand); | 695 Mov(temp, operand); |
| 671 AddSub(rd, rn, temp, S, op); | 696 AddSub(rd, rn, temp, S, op); |
| 672 } | 697 } |
| 673 } else { | 698 } else { |
| 674 AddSub(rd, rn, operand, S, op); | 699 AddSub(rd, rn, operand, S, op); |
| 675 } | 700 } |
| 676 } | 701 } |
| 677 | 702 |
| (...skipping 4091 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4769 } | 4794 } |
| 4770 | 4795 |
| 4771 | 4796 |
| 4772 #undef __ | 4797 #undef __ |
| 4773 | 4798 |
| 4774 | 4799 |
| 4775 } // namespace internal | 4800 } // namespace internal |
| 4776 } // namespace v8 | 4801 } // namespace v8 |
| 4777 | 4802 |
| 4778 #endif // V8_TARGET_ARCH_ARM64 | 4803 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |