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..9e386dd3d8538c30815c07516cedf3e46b2383be 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,17 +607,23 @@ 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. |
if (TryOneInstrMoveImmediate(dst, imm)) { |
// The move was successful; nothing to do here. |
} 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 |
@@ -621,13 +632,13 @@ Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst, |
// If this new immediate is encodable, the set bits will be eliminated by |
// the post shift on the following instruction. |
int shift_high = CountLeadingZeros(imm, reg_size); |
- int64_t imm_high = (imm << shift_high) | ((1 << shift_high) - 1); |
+ int64_t imm_high = (imm << shift_high) | ((INT64_C(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 +674,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); |