Chromium Code Reviews| Index: src/arm/assembler-arm.cc |
| diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc |
| index ccf7208a8f6aa6c56cb73483d66a2a3ca1cca79d..68bb8783cd5d9bb56bfc5a497e69d83815c332ec 100644 |
| --- a/src/arm/assembler-arm.cc |
| +++ b/src/arm/assembler-arm.cc |
| @@ -117,6 +117,10 @@ void CpuFeatures::Probe() { |
| if (FLAG_enable_sudiv) { |
| supported_ |= 1u << SUDIV; |
| } |
| + |
| + if (FLAG_enable_movw_movt) { |
| + supported_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; |
| + } |
| #else // __arm__ |
| // Probe for additional features not already known to be available. |
| if (!IsSupported(VFP3) && OS::ArmCpuHasFeature(VFP3)) { |
| @@ -140,6 +144,11 @@ void CpuFeatures::Probe() { |
| found_by_runtime_probing_ |= 1u << UNALIGNED_ACCESSES; |
| } |
| + if (OS::GetCpuImplementer() == QualcommImplementer && |
| + OS::ArmCpuHasFeature(ARMv7)) { |
| + found_by_runtime_probing_ |= 1u << MOVW_MOVT_IMMEDIATE_LOADS; |
| + } |
| + |
| supported_ |= found_by_runtime_probing_; |
| #endif |
| @@ -730,12 +739,6 @@ void Assembler::next(Label* L) { |
| } |
| -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 |
| @@ -800,7 +803,7 @@ static bool fits_shifter(uint32_t imm32, |
| // 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. |
| -bool Operand::must_use_constant_pool(const Assembler* assembler) const { |
| +bool Operand::must_output_reloc_info(const Assembler* assembler) const { |
| if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) { |
| #ifdef DEBUG |
| if (!Serializer::enabled()) { |
| @@ -820,21 +823,25 @@ bool Operand::is_single_instruction(const Assembler* assembler, |
| Instr instr) const { |
| if (rm_.is_valid()) return true; |
| uint32_t dummy1, dummy2; |
| - if (must_use_constant_pool(assembler) || |
| + if (must_output_reloc_info(assembler) || |
| !fits_shifter(imm32_, &dummy1, &dummy2, &instr)) { |
| // The immediate operand cannot be encoded as a shifter operand, or use of |
| // constant pool is required. For a mov instruction not setting the |
| // condition code additional instruction conventions can be used. |
| if ((instr & ~kCondMask) == 13*B21) { // mov, S not set |
| - if (must_use_constant_pool(assembler) || |
| - !CpuFeatures::IsSupported(ARMv7)) { |
| - // mov instruction will be an ldr from constant pool (one instruction). |
| - return true; |
| - } else { |
| - // mov instruction will be a mov or movw followed by movt (two |
| - // instructions). |
| - return false; |
| - } |
| +#ifdef USE_BLX |
| + // When using BLX, there are two things that must be true for the address |
| + // load to be longer than a single instruction. First, immediate loads |
| + // using movw/movt must be supported (and fast) on the target ARM |
| + // architecture. Second, the reloc mode must be something other than NONE, |
| + // since NONE is a used whenever the constant pool cannot be used for |
| + // technical reasons, e.g. back-patching calls site in optimized code with |
| + // a call to a lazy deopt routine. |
| + return !Assembler::allow_immediate_constant_pool_loads(assembler) && |
| + rmode_ != RelocInfo::NONE; |
| +#else |
| + return true; |
|
ulan
2012/10/18 09:07:53
Why don't we check for !CpuFeatures::IsSupported(A
danno
2012/10/18 12:22:10
It's not possible to use immediate loads to the pc
|
| +#endif |
| } else { |
| // If this is not a mov or mvn instruction there will always an additional |
| // instructions - either mov or ldr. The mov might actually be two |
| @@ -850,6 +857,34 @@ bool Operand::is_single_instruction(const Assembler* assembler, |
| } |
| +void Assembler::move_32_bit_immediate(Condition cond, |
| + Register rd, |
| + SBit s, |
| + const Operand& x) { |
| + if (rd.code() != pc.code() && s == LeaveCC) { |
| + // Candidate for immediate load. |
| + if (x.must_output_reloc_info(this)) { |
| + if (!Assembler::allow_immediate_constant_pool_loads(this)) { |
| + RecordRelocInfo(x.rmode_, x.imm32_, USE_CONSTANT_POOL); |
| + ldr(rd, MemOperand(pc, 0), cond); |
| + return; |
| + } |
| + RecordRelocInfo(x.rmode_, x.imm32_, DONT_USE_CONSTANT_POOL); |
| + // Make sure the movw/movt doesn't get separated. |
| + BlockConstPoolFor(2); |
| + } |
| + |
| + // Emit a real movw/movt pair. |
| + emit(cond | 0x30*B20 | rd.code()*B12 | |
| + EncodeMovwImmediate(x.imm32_ & 0xffff)); |
| + movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond); |
| + } else { |
| + RecordRelocInfo(x.rmode_, x.imm32_, USE_CONSTANT_POOL); |
| + ldr(rd, MemOperand(pc, 0), cond); |
| + } |
| +} |
| + |
| + |
| void Assembler::addrmod1(Instr instr, |
| Register rn, |
| Register rd, |
| @@ -860,7 +895,7 @@ void Assembler::addrmod1(Instr instr, |
| // Immediate. |
| uint32_t rotate_imm; |
| uint32_t immed_8; |
| - if (x.must_use_constant_pool(this) || |
| + if (x.must_output_reloc_info(this) || |
| !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. |
| @@ -869,24 +904,16 @@ void Assembler::addrmod1(Instr instr, |
| CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed |
| Condition cond = Instruction::ConditionField(instr); |
| if ((instr & ~kCondMask) == 13*B21) { // mov, S not set |
| - if (x.must_use_constant_pool(this) || |
| - !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); |
| - } |
| + move_32_bit_immediate(cond, rd, LeaveCC, x); |
| } else { |
| // 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 (!x.must_use_constant_pool(this) && |
| + if (!x.must_output_reloc_info(this) && |
| (instr & kMovMvnMask) != kMovMvnPattern) { |
| mov(ip, x, LeaveCC, cond); |
| } else { |
| - RecordRelocInfo(x.rmode_, x.imm32_); |
| - ldr(ip, MemOperand(pc, 0), cond); |
| + move_32_bit_immediate(cond, ip, |
| + static_cast<SBit>(instr & (1 << 20)), x); |
| } |
| addrmod1(instr, rn, rd, Operand(ip)); |
| } |
| @@ -1193,6 +1220,9 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { |
| void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { |
| ASSERT(immediate < 0x10000); |
| + // May use movw if supported, but on unsupported platforms will try to use |
| + // equivalent rotated immed_8 value and other tricks before falling back to a |
| + // constant pool load. |
| mov(reg, Operand(immediate), LeaveCC, cond); |
| } |
| @@ -1422,7 +1452,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src, |
| // Immediate. |
| uint32_t rotate_imm; |
| uint32_t immed_8; |
| - if (src.must_use_constant_pool(this) || |
| + if (src.must_output_reloc_info(this) || |
| !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_); |
| @@ -2450,6 +2480,22 @@ void Assembler::nop(int type) { |
| } |
| +bool Assembler::IsMovT(Instr instr) { |
| + instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions |
| + ((kNumRegisters-1)*B12) | // mask out register |
| + EncodeMovwImmediate(0xFFFF)); // mask out immediate value |
| + return instr == 0x34*B20; |
| +} |
| + |
| + |
| +bool Assembler::IsMovW(Instr instr) { |
| + instr &= ~(((kNumberOfConditions - 1) << 28) | // Mask off conditions |
| + ((kNumRegisters-1)*B12) | // mask out destination |
| + EncodeMovwImmediate(0xFFFF)); // mask out immediate value |
| + return instr == 0x30*B20; |
| +} |
| + |
| + |
| bool Assembler::IsNop(Instr instr, int type) { |
| ASSERT(0 <= type && type <= 14); // mov pc, pc isn't a nop. |
| // Check for mov rx, rx where x = type. |
| @@ -2568,18 +2614,21 @@ void Assembler::dd(uint32_t data) { |
| } |
| -void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
| +void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data, |
| + UseConstantPoolMode mode) { |
| // We do not try to reuse pool constants. |
| RelocInfo rinfo(pc_, rmode, data, NULL); |
| if (((rmode >= RelocInfo::JS_RETURN) && |
| (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) || |
| - (rmode == RelocInfo::CONST_POOL)) { |
| + (rmode == RelocInfo::CONST_POOL) || |
| + mode == DONT_USE_CONSTANT_POOL) { |
| // Adjust code for new modes. |
| ASSERT(RelocInfo::IsDebugBreakSlot(rmode) |
| || RelocInfo::IsJSReturn(rmode) |
| || RelocInfo::IsComment(rmode) |
| || RelocInfo::IsPosition(rmode) |
| - || RelocInfo::IsConstPool(rmode)); |
| + || RelocInfo::IsConstPool(rmode) |
| + || mode == DONT_USE_CONSTANT_POOL); |
| // These modes do not need an entry in the constant pool. |
| } else { |
| ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo); |
| @@ -2698,17 +2747,19 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { |
| Instr instr = instr_at(rinfo.pc()); |
| // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0. |
| - ASSERT(IsLdrPcImmediateOffset(instr) && |
| - GetLdrRegisterImmediateOffset(instr) == 0); |
| - |
| - int delta = pc_ - rinfo.pc() - kPcLoadDelta; |
| - // 0 is the smallest delta: |
| - // ldr rd, [pc, #0] |
| - // constant pool marker |
| - // data |
| - ASSERT(is_uint12(delta)); |
| - |
| - instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); |
| + if (IsLdrPcImmediateOffset(instr) && |
| + GetLdrRegisterImmediateOffset(instr) == 0) { |
| + int delta = pc_ - rinfo.pc() - kPcLoadDelta; |
| + // 0 is the smallest delta: |
| + // ldr rd, [pc, #0] |
| + // constant pool marker |
| + // data |
| + ASSERT(is_uint12(delta)); |
| + |
| + instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); |
| + } else { |
| + ASSERT(IsMovW(instr)); |
| + } |
| emit(rinfo.data()); |
| } |