Skip to content

Commit

Permalink
ARM64: Generate better immediates for shifted ops
Browse files Browse the repository at this point in the history
Improve code generated for immediate data processing operations where the shift
on the operation can be exploited to use fewer instructions for the immediate.

For example, Add(x0, x0, 0x1f7de) used to generate:
  movz x16, 0xf7de
  movk x16, 0x1, lsl #16
  add x0, x0, x16

now generates:
  movz x16, 0xfbef
  add x0, x0, x16, lsl #1

BUG=
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/368313002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22246 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
  • Loading branch information
m.m.capewell@googlemail.com committed Jul 7, 2014
1 parent 1471c64 commit 493b64e
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 23 deletions.
12 changes: 8 additions & 4 deletions src/arm64/macro-assembler-arm64-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ void MacroAssembler::Add(const Register& rd,
const Register& rn,
const Operand& operand) {
ASSERT(allow_macro_instructions_);
if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
IsImmAddSub(-operand.ImmediateValue())) {
AddSubMacro(rd, rn, -operand.ImmediateValue(), LeaveFlags, SUB);
} else {
AddSubMacro(rd, rn, operand, LeaveFlags, ADD);
Expand All @@ -162,7 +163,8 @@ void MacroAssembler::Adds(const Register& rd,
const Register& rn,
const Operand& operand) {
ASSERT(allow_macro_instructions_);
if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
IsImmAddSub(-operand.ImmediateValue())) {
AddSubMacro(rd, rn, -operand.ImmediateValue(), SetFlags, SUB);
} else {
AddSubMacro(rd, rn, operand, SetFlags, ADD);
Expand All @@ -174,7 +176,8 @@ void MacroAssembler::Sub(const Register& rd,
const Register& rn,
const Operand& operand) {
ASSERT(allow_macro_instructions_);
if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
IsImmAddSub(-operand.ImmediateValue())) {
AddSubMacro(rd, rn, -operand.ImmediateValue(), LeaveFlags, ADD);
} else {
AddSubMacro(rd, rn, operand, LeaveFlags, SUB);
Expand All @@ -186,7 +189,8 @@ void MacroAssembler::Subs(const Register& rd,
const Register& rn,
const Operand& operand) {
ASSERT(allow_macro_instructions_);
if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
IsImmAddSub(-operand.ImmediateValue())) {
AddSubMacro(rd, rn, -operand.ImmediateValue(), SetFlags, ADD);
} else {
AddSubMacro(rd, rn, operand, SetFlags, SUB);
Expand Down
95 changes: 76 additions & 19 deletions src/arm64/macro-assembler-arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,15 @@ void MacroAssembler::LogicalMacro(const Register& rd,
} else {
// Immediate can't be encoded: synthesize using move immediate.
Register temp = temps.AcquireSameSizeAs(rn);
Mov(temp, immediate);
Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
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.
Logical(temp, rn, temp, op);
Logical(temp, rn, imm_operand, op);
Mov(csp, temp);
AssertStackConsistency();
} else {
Logical(rd, rn, temp, op);
Logical(rd, rn, imm_operand, op);
}
}

Expand Down Expand Up @@ -178,20 +178,11 @@ void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
// applying move-keep operations to move-zero and move-inverted initial
// values.

unsigned reg_size = rd.SizeInBits();
unsigned n, imm_s, imm_r;
if (IsImmMovz(imm, reg_size) && !rd.IsSP()) {
// Immediate can be represented in a move zero instruction. Movz can't
// write to the stack pointer.
movz(rd, imm);
} else if (IsImmMovn(imm, reg_size) && !rd.IsSP()) {
// Immediate can be represented in a move inverted instruction. Movn can't
// write to the stack pointer.
movn(rd, rd.Is64Bits() ? ~imm : (~imm & kWRegMask));
} else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
// Immediate can be represented in a logical orr instruction.
LogicalImmediate(rd, AppropriateZeroRegFor(rd), n, imm_s, imm_r, ORR);
} else {
// Try to move the immediate in one instruction, and if that fails, switch to
// using multiple instructions.
if (!TryOneInstrMoveImmediate(rd, imm)) {
unsigned reg_size = rd.SizeInBits();

// Generic immediate case. Imm will be represented by
// [imm3, imm2, imm1, imm0], where each imm is 16 bits.
// A move-zero or move-inverted is generated for the first non-zero or
Expand Down Expand Up @@ -419,6 +410,66 @@ void MacroAssembler::Csel(const Register& rd,
}


bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
int64_t imm) {
unsigned n, imm_s, imm_r;
int reg_size = dst.SizeInBits();
if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {
// Immediate can be represented in a move zero instruction. Movz can't write
// to the stack pointer.
movz(dst, imm);
return true;
} else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {
// Immediate can be represented in a move not instruction. Movn can't write
// to the stack pointer.
movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));
return true;
} else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
// Immediate can be represented in a logical orr instruction.
LogicalImmediate(dst, AppropriateZeroRegFor(dst), n, imm_s, imm_r, ORR);
return true;
}
return false;
}


Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
int64_t imm) {
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);
int64_t imm_low = imm >> shift_low;

// Pre-shift the immediate to the most-significant bits of the register. We
// insert set bits in the least-significant bits, as this creates a
// different immediate that may be encodable using movn or orr-immediate.
// 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);

if (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)) {
// The new immediate has been moved into the destination's high bits:
// return a new rightward-shifting operand.
return Operand(dst, LSR, shift_high);
} else {
// Use the generic move operation to set up the immediate.
Mov(dst, imm);
}
}
return Operand(dst);
}


void MacroAssembler::AddSubMacro(const Register& rd,
const Register& rn,
const Operand& operand,
Expand All @@ -441,8 +492,14 @@ void MacroAssembler::AddSubMacro(const Register& rd,
(operand.IsShiftedRegister() && (operand.shift() == ROR))) {
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireSameSizeAs(rn);
Mov(temp, operand);
AddSub(rd, rn, temp, S, op);
if (operand.IsImmediate()) {
Operand imm_operand =
MoveImmediateForShiftedOp(temp, operand.ImmediateValue());
AddSub(rd, rn, imm_operand, S, op);
} else {
Mov(temp, operand);
AddSub(rd, rn, temp, S, op);
}
} else {
AddSub(rd, rn, operand, S, op);
}
Expand Down
12 changes: 12 additions & 0 deletions src/arm64/macro-assembler-arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,18 @@ class MacroAssembler : public Assembler {
static bool IsImmMovz(uint64_t imm, unsigned reg_size);
static unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size);

// Try to move an immediate into the destination register in a single
// instruction. Returns true for success, and updates the contents of dst.
// Returns false, otherwise.
bool TryOneInstrMoveImmediate(const Register& dst, int64_t imm);

// Move an immediate into register dst, and return an Operand object for use
// with a subsequent instruction that accepts a shift. The value moved into
// dst is not necessarily equal to imm; it may have had a shifting operation
// applied to it that will be subsequently undone by the shift applied in the
// Operand.
Operand MoveImmediateForShiftedOp(const Register& dst, int64_t imm);

// Conditional macros.
inline void Ccmp(const Register& rn,
const Operand& operand,
Expand Down

0 comments on commit 493b64e

Please sign in to comment.