aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartyn Capewell <martyn.capewell@arm.com>2020-07-01 11:01:51 +0100
committerJacob Bramley <jacob.bramley@arm.com>2020-07-13 20:05:18 +0000
commit960606b686f59d468f97dfa93b5dba5b2b38cc8f (patch)
tree3948abaa2c6f91c5259c81ddb1262f662474034f /src
parent4635261c9edcf4b056f9e1b26052b5612dee61ba (diff)
downloadvixl-960606b686f59d468f97dfa93b5dba5b2b38cc8f.tar.gz
Emit pairs of add/sub for larger immediates
For immediates between 12 and 24 bits in size, a pair of add or sub instructions can be used instead of mov, avoiding the need to allocate a temporary. Change-Id: I114b4667dcc1bda094652e01d88069d012249dca
Diffstat (limited to 'src')
-rw-r--r--src/aarch64/macro-assembler-aarch64.cc44
1 files changed, 25 insertions, 19 deletions
diff --git a/src/aarch64/macro-assembler-aarch64.cc b/src/aarch64/macro-assembler-aarch64.cc
index 1e81a8d7..0d9f0ec0 100644
--- a/src/aarch64/macro-assembler-aarch64.cc
+++ b/src/aarch64/macro-assembler-aarch64.cc
@@ -1427,8 +1427,7 @@ void MacroAssembler::Add(const Register& rd,
const Operand& operand,
FlagsUpdate S) {
VIXL_ASSERT(allow_macro_instructions_);
- if (operand.IsImmediate() && (operand.GetImmediate() < 0) &&
- IsImmAddSub(-operand.GetImmediate())) {
+ if (operand.IsImmediate() && (operand.GetImmediate() < 0)) {
AddSubMacro(rd, rn, -operand.GetImmediate(), S, SUB);
} else {
AddSubMacro(rd, rn, operand, S, ADD);
@@ -1448,8 +1447,7 @@ void MacroAssembler::Sub(const Register& rd,
const Operand& operand,
FlagsUpdate S) {
VIXL_ASSERT(allow_macro_instructions_);
- if (operand.IsImmediate() && (operand.GetImmediate() < 0) &&
- IsImmAddSub(-operand.GetImmediate())) {
+ if (operand.IsImmediate() && (operand.GetImmediate() < 0)) {
AddSubMacro(rd, rn, -operand.GetImmediate(), S, ADD);
} else {
AddSubMacro(rd, rn, operand, S, SUB);
@@ -1774,22 +1772,30 @@ void MacroAssembler::AddSubMacro(const Register& rd,
// `rd`) because we don't need it after it is evaluated.
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.IsSP()) {
- // 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.IsSP()) {
- mode = kLimitShiftForSP;
- }
+ int64_t imm = operand.GetImmediate();
+ int64_t divisor = 1 << ImmAddSub_width;
+ if ((S == LeaveFlags) && IsUint12(imm / divisor)) {
+ // Unsigned immediates requiring up to 24 bits are emitted as two adds
+ // or subs.
+ AddSub(rd, rn, imm % divisor, S, op);
+ AddSub(rd, rd, (imm / divisor) << ImmAddSub_width, S, op);
+ } else {
+ 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.IsSP()) {
+ // 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.IsSP()) {
+ mode = kLimitShiftForSP;
+ }
- Operand imm_operand =
- MoveImmediateForShiftedOp(temp, operand.GetImmediate(), mode);
- AddSub(rd, rn, imm_operand, S, op);
+ Operand imm_operand = MoveImmediateForShiftedOp(temp, imm, mode);
+ AddSub(rd, rn, imm_operand, S, op);
+ }
} else {
Mov(temp, operand);
AddSub(rd, rn, temp, S, op);