| Index: src/arm/assembler-arm.cc
|
| diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
|
| index ccf7208a8f6aa6c56cb73483d66a2a3ca1cca79d..cc3d5b11a323801f69ecdbc630b37a54a932c74e 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() == QUALCOMM_IMPLEMENTER &&
|
| + 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,29 @@ 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
|
| + // It's not possible to use immediate loads to the pc to do a call, (the
|
| + // pc would be inconsistent half-way through the load), so loading the
|
| + // destination address without USE_BLX is always a single instruction of
|
| + // the form ldr pc, [pc + #xxx].
|
| + return true;
|
| +#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 +861,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 +899,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 +908,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 +1224,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 +1456,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 +2484,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 +2618,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 +2751,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());
|
| }
|
|
|
|
|