Index: src/arm/assembler-arm.cc |
=================================================================== |
--- src/arm/assembler-arm.cc (revision 4906) |
+++ src/arm/assembler-arm.cc (working copy) |
@@ -282,6 +282,11 @@ |
const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16; |
const Instr kMovMvnPattern = 0xd * B21; |
const Instr kMovMvnFlip = B22; |
+const Instr kMovLeaveCCMask = 0xdff * B16; |
+const Instr kMovLeaveCCPattern = 0x1a0 * B16; |
+const Instr kMovwMask = 0xff * B20; |
+const Instr kMovwPattern = 0x30 * B20; |
+const Instr kMovwLeaveCCFlip = 0x5 * B21; |
const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12; |
const Instr kCmpCmnPattern = 0x15 * B20; |
const Instr kCmpCmnFlip = B21; |
@@ -640,6 +645,12 @@ |
} |
+static Instr EncodeMovwImmediate(uint32_t immediate) { |
+ ASSERT(immediate < 0x10000); |
+ return ((immediate & 0xf000) << 4) | (immediate & 0xfff); |
+} |
+ |
+ |
// Low-level code emission routines depending on the addressing mode. |
// If this returns true then you have to use the rotate_imm and immed_8 |
// that it returns, because it may have already changed the instruction |
@@ -664,6 +675,15 @@ |
if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) { |
*instr ^= kMovMvnFlip; |
return true; |
+ } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) { |
+ if (CpuFeatures::IsSupported(ARMv7)) { |
+ if (imm32 < 0x10000) { |
+ *instr ^= kMovwLeaveCCFlip; |
+ *instr |= EncodeMovwImmediate(imm32); |
+ *rotate_imm = *immed_8 = 0; // Not used for movw. |
+ return true; |
+ } |
+ } |
} |
} else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) { |
if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) { |
@@ -695,7 +715,7 @@ |
// if they can be encoded in the ARM's 12 bits of immediate-offset instruction |
// space. There is no guarantee that the relocated location can be similarly |
// encoded. |
-static bool MustUseIp(RelocInfo::Mode rmode) { |
+static bool MustUseConstantPool(RelocInfo::Mode rmode) { |
if (rmode == RelocInfo::EXTERNAL_REFERENCE) { |
#ifdef DEBUG |
if (!Serializer::enabled()) { |
@@ -712,7 +732,7 @@ |
bool Operand::is_single_instruction() const { |
if (rm_.is_valid()) return true; |
- if (MustUseIp(rmode_)) return false; |
+ if (MustUseConstantPool(rmode_)) return false; |
uint32_t dummy1, dummy2; |
return fits_shifter(imm32_, &dummy1, &dummy2, NULL); |
} |
@@ -728,19 +748,34 @@ |
// Immediate. |
uint32_t rotate_imm; |
uint32_t immed_8; |
- if (MustUseIp(x.rmode_) || |
+ if (MustUseConstantPool(x.rmode_) || |
!fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) { |
// The immediate operand cannot be encoded as a shifter operand, so load |
// it first to register ip and change the original instruction to use ip. |
// However, if the original instruction is a 'mov rd, x' (not setting the |
// condition code), then replace it with a 'ldr rd, [pc]'. |
- RecordRelocInfo(x.rmode_, x.imm32_); |
CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed |
Condition cond = static_cast<Condition>(instr & CondMask); |
if ((instr & ~CondMask) == 13*B21) { // mov, S not set |
- ldr(rd, MemOperand(pc, 0), cond); |
+ if (MustUseConstantPool(x.rmode_) || |
+ !CpuFeatures::IsSupported(ARMv7)) { |
+ RecordRelocInfo(x.rmode_, x.imm32_); |
+ ldr(rd, MemOperand(pc, 0), cond); |
+ } else { |
+ // Will probably use movw, will certainly not use constant pool. |
+ mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond); |
+ movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond); |
+ } |
} else { |
- ldr(ip, MemOperand(pc, 0), cond); |
+ // If this is not a mov or mvn instruction we may still be able to avoid |
+ // a constant pool entry by using mvn or movw. |
+ if (!MustUseConstantPool(x.rmode_) && |
+ (instr & kMovMvnMask) != kMovMvnPattern) { |
+ mov(ip, x, LeaveCC, cond); |
+ } else { |
+ RecordRelocInfo(x.rmode_, x.imm32_); |
+ ldr(ip, MemOperand(pc, 0), cond); |
+ } |
addrmod1(instr, rn, rd, Operand(ip)); |
} |
return; |
@@ -1051,6 +1086,11 @@ |
} |
+void Assembler::movt(Register reg, uint32_t immediate, Condition cond) { |
+ emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate)); |
+} |
+ |
+ |
void Assembler::bic(Register dst, Register src1, const Operand& src2, |
SBit s, Condition cond) { |
addrmod1(cond | 14*B21 | s, src1, dst, src2); |
@@ -1231,7 +1271,7 @@ |
// Immediate. |
uint32_t rotate_imm; |
uint32_t immed_8; |
- if (MustUseIp(src.rmode_) || |
+ if (MustUseConstantPool(src.rmode_) || |
!fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) { |
// Immediate operand cannot be encoded, load it first to register ip. |
RecordRelocInfo(src.rmode_, src.imm32_); |