ARM64: Generate better immediates for shifted ops

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
This commit is contained in:
m.m.capewell@googlemail.com 2014-07-07 13:31:22 +00:00
parent cef7b20ec0
commit 45e451183e
3 changed files with 96 additions and 23 deletions

View File

@ -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);
@ -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);
@ -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);
@ -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);

View File

@ -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);
}
}
@ -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
@ -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,
@ -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);
}

View File

@ -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,