| Index: src/arm64/macro-assembler-arm64.cc
|
| diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc
|
| index 4d02475c2de7088531a207b2e1c6d8395a49691b..2e9b0f5b3f8b8c0c96fe1d51b1c1ffa0f9f9f34c 100644
|
| --- a/src/arm64/macro-assembler-arm64.cc
|
| +++ b/src/arm64/macro-assembler-arm64.cc
|
| @@ -129,7 +129,12 @@ void MacroAssembler::LogicalMacro(const Register& rd,
|
| } else {
|
| // Immediate can't be encoded: synthesize using move immediate.
|
| Register temp = temps.AcquireSameSizeAs(rn);
|
| - Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
|
| +
|
| + // If the left-hand input is the stack pointer, we can't pre-shift the
|
| + // immediate, as the encoding won't allow the subsequent post shift.
|
| + PreShiftImmMode mode = rn.Is(csp) ? kNoShift : kAnyShift;
|
| + Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate, mode);
|
| +
|
| if (rd.Is(csp)) {
|
| // If rd is the stack pointer we cannot use it as the destination
|
| // register so we use the temp register as an intermediate again.
|
| @@ -602,9 +607,9 @@ bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
|
| return false;
|
| }
|
|
|
| -
|
| Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
|
| - int64_t imm) {
|
| + int64_t imm,
|
| + PreShiftImmMode mode) {
|
| int reg_size = dst.SizeInBits();
|
|
|
| // Encode the immediate in a single move instruction, if possible.
|
| @@ -613,6 +618,13 @@ Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
|
| } else {
|
| // Pre-shift the immediate to the least-significant bits of the register.
|
| int shift_low = CountTrailingZeros(imm, reg_size);
|
| + if (mode == kLimitShiftForSP) {
|
| + // When applied to the stack pointer, the subsequent arithmetic operation
|
| + // can use the extend form to shift left by a maximum of four bits. Right
|
| + // shifts are not allowed, so we filter them out later before the new
|
| + // immediate is tested.
|
| + shift_low = std::min(shift_low, 4);
|
| + }
|
| int64_t imm_low = imm >> shift_low;
|
|
|
| // Pre-shift the immediate to the most-significant bits of the register. We
|
| @@ -623,11 +635,11 @@ Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
|
| int shift_high = CountLeadingZeros(imm, reg_size);
|
| int64_t imm_high = (imm << shift_high) | ((1 << shift_high) - 1);
|
|
|
| - if (TryOneInstrMoveImmediate(dst, imm_low)) {
|
| + if ((mode != kNoShift) && TryOneInstrMoveImmediate(dst, imm_low)) {
|
| // The new immediate has been moved into the destination's low bits:
|
| // return a new leftward-shifting operand.
|
| return Operand(dst, LSL, shift_low);
|
| - } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
|
| + } else if ((mode == kAnyShift) && TryOneInstrMoveImmediate(dst, imm_high)) {
|
| // The new immediate has been moved into the destination's high bits:
|
| // return a new rightward-shifting operand.
|
| return Operand(dst, LSR, shift_high);
|
| @@ -663,8 +675,21 @@ void MacroAssembler::AddSubMacro(const Register& rd,
|
| UseScratchRegisterScope temps(this);
|
| Register temp = temps.AcquireSameSizeAs(rn);
|
| if (operand.IsImmediate()) {
|
| + PreShiftImmMode mode = kAnyShift;
|
| +
|
| + // If the destination or source register is the stack pointer, we can
|
| + // only pre-shift the immediate right by values supported in the add/sub
|
| + // extend encoding.
|
| + if (rd.Is(csp)) {
|
| + // If the destination is SP and flags will be set, we can't pre-shift
|
| + // the immediate at all.
|
| + mode = (S == SetFlags) ? kNoShift : kLimitShiftForSP;
|
| + } else if (rn.Is(csp)) {
|
| + mode = kLimitShiftForSP;
|
| + }
|
| +
|
| Operand imm_operand =
|
| - MoveImmediateForShiftedOp(temp, operand.ImmediateValue());
|
| + MoveImmediateForShiftedOp(temp, operand.ImmediateValue(), mode);
|
| AddSub(rd, rn, imm_operand, S, op);
|
| } else {
|
| Mov(temp, operand);
|
|
|