 Chromium Code Reviews
 Chromium Code Reviews Issue 11037023:
  Use movw/movt instead of constant pool on ARMv7  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 11037023:
  Use movw/movt instead of constant pool on ARMv7  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/arm/assembler-arm.cc | 
| diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc | 
| index 7a65ab25cb745beafe7a371079440b2593a2753b..d6d995321660df061388be062f84a3da71cd958a 100644 | 
| --- a/src/arm/assembler-arm.cc | 
| +++ b/src/arm/assembler-arm.cc | 
| @@ -723,12 +723,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 | 
| @@ -793,7 +787,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()) { | 
| @@ -813,21 +807,17 @@ 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 | 
| + return !Assembler::allow_immediate_constant_pool_loads(assembler); | 
| +#else | 
| + return true; | 
| 
Michael Starzinger
2012/10/10 14:19:29
Indentation is off.
 
danno
2012/10/17 10:04:44
Done.
 
danno
2012/10/17 10:04:44
Done.
 | 
| +#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 | 
| @@ -843,6 +833,29 @@ bool Operand::is_single_instruction(const Assembler* assembler, | 
| } | 
| +void Assembler::move_32_bit_immediate(Condition cond, | 
| + Register rd, | 
| + SBit s, | 
| + const Operand& x) { | 
| + if (Assembler::allow_immediate_constant_pool_loads(this) && | 
| + rd.code() != pc.code() && | 
| + s == LeaveCC) { | 
| 
Please use jfb - chromium.org
2012/10/10 13:56:52
In this case we're emitting 2 instructions, and wh
 
danno
2012/10/17 10:04:44
I solved this a little differently. Embedded objec
 | 
| + if (x.must_output_reloc_info(this)) { | 
| + RecordRelocInfo(x.rmode_, x.imm32_, DONT_USE_CONSTANT_POOL); | 
| 
Please use jfb - chromium.org
2012/10/10 13:56:52
As before, if there's relocinfo then it's code (ri
 
Michael Starzinger
2012/10/10 14:34:29
I am not sure about this. We also have RelocInfos
 
danno
2012/10/17 10:04:44
For object pointers, the address is not aligned, s
 | 
| + } | 
| + BlockConstPoolFor(2); | 
| + | 
| + // Emit a "real" movw | 
| + 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_); | 
| + ldr(rd, MemOperand(pc, 0), cond); | 
| + } | 
| +} | 
| + | 
| + | 
| void Assembler::addrmod1(Instr instr, | 
| Register rn, | 
| Register rd, | 
| @@ -853,7 +866,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. | 
| @@ -862,24 +875,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)); | 
| } | 
| @@ -1186,6 +1191,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); | 
| } | 
| @@ -1415,7 +1423,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_); | 
| @@ -2439,6 +2447,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) { | 
| // Check for mov rx, rx where x = type. | 
| ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop. | 
| @@ -2557,18 +2581,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); | 
| @@ -2687,17 +2714,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()); | 
| } |