| 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()); | 
| } | 
|  | 
|  |