| Index: src/arm/assembler-arm.cc
|
| ===================================================================
|
| --- src/arm/assembler-arm.cc (revision 4699)
|
| +++ src/arm/assembler-arm.cc (working copy)
|
| @@ -36,6 +36,8 @@
|
|
|
| #include "v8.h"
|
|
|
| +#if defined(V8_TARGET_ARCH_ARM)
|
| +
|
| #include "arm/assembler-arm-inl.h"
|
| #include "serialize.h"
|
|
|
| @@ -106,6 +108,15 @@
|
| const int RelocInfo::kApplyMask = 0;
|
|
|
|
|
| +bool RelocInfo::IsCodedSpecially() {
|
| + // The deserializer needs to know whether a pointer is specially coded. Being
|
| + // specially coded on ARM means that it is a movw/movt instruction. We don't
|
| + // generate those yet.
|
| + return false;
|
| +}
|
| +
|
| +
|
| +
|
| void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
|
| // Patch the code at the current address with the supplied instructions.
|
| Instr* pc = reinterpret_cast<Instr*>(pc_);
|
| @@ -268,6 +279,20 @@
|
| 15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
|
| const Instr kBlxRegPattern =
|
| B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | 3 * B4;
|
| +// A mask for the Rd register for push, pop, ldr, str instructions.
|
| +const Instr kRdMask = 0x0000f000;
|
| +static const int kRdShift = 12;
|
| +static const Instr kLdrRegFpOffsetPattern =
|
| + al | B26 | L | Offset | fp.code() * B16;
|
| +static const Instr kStrRegFpOffsetPattern =
|
| + al | B26 | Offset | fp.code() * B16;
|
| +static const Instr kLdrRegFpNegOffsetPattern =
|
| + al | B26 | L | NegOffset | fp.code() * B16;
|
| +static const Instr kStrRegFpNegOffsetPattern =
|
| + al | B26 | NegOffset | fp.code() * B16;
|
| +static const Instr kLdrStrInstrTypeMask = 0xffff0000;
|
| +static const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
|
| +static const Instr kLdrStrOffsetMask = 0x00000fff;
|
|
|
| // Spare buffer.
|
| static const int kMinimalBufferSize = 4*KB;
|
| @@ -395,6 +420,43 @@
|
| }
|
|
|
|
|
| +Register Assembler::GetRd(Instr instr) {
|
| + Register reg;
|
| + reg.code_ = ((instr & kRdMask) >> kRdShift);
|
| + return reg;
|
| +}
|
| +
|
| +
|
| +bool Assembler::IsPush(Instr instr) {
|
| + return ((instr & ~kRdMask) == kPushRegPattern);
|
| +}
|
| +
|
| +
|
| +bool Assembler::IsPop(Instr instr) {
|
| + return ((instr & ~kRdMask) == kPopRegPattern);
|
| +}
|
| +
|
| +
|
| +bool Assembler::IsStrRegFpOffset(Instr instr) {
|
| + return ((instr & kLdrStrInstrTypeMask) == kStrRegFpOffsetPattern);
|
| +}
|
| +
|
| +
|
| +bool Assembler::IsLdrRegFpOffset(Instr instr) {
|
| + return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpOffsetPattern);
|
| +}
|
| +
|
| +
|
| +bool Assembler::IsStrRegFpNegOffset(Instr instr) {
|
| + return ((instr & kLdrStrInstrTypeMask) == kStrRegFpNegOffsetPattern);
|
| +}
|
| +
|
| +
|
| +bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
|
| + return ((instr & kLdrStrInstrTypeMask) == kLdrRegFpNegOffsetPattern);
|
| +}
|
| +
|
| +
|
| // Labels refer to positions in the (to be) generated code.
|
| // There are bound, linked, and unused labels.
|
| //
|
| @@ -887,15 +949,12 @@
|
| // str(src, MemOperand(sp, 4, NegPreIndex), al);
|
| // add(sp, sp, Operand(kPointerSize));
|
| // Both instructions can be eliminated.
|
| - int pattern_size = 2 * kInstrSize;
|
| - if (FLAG_push_pop_elimination &&
|
| - last_bound_pos_ <= (pc_offset() - pattern_size) &&
|
| - reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
|
| + if (can_peephole_optimize(2) &&
|
| // Pattern.
|
| instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
|
| (instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) {
|
| pc_ -= 2 * kInstrSize;
|
| - if (FLAG_print_push_pop_elimination) {
|
| + if (FLAG_print_peephole_optimization) {
|
| PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
|
| }
|
| }
|
| @@ -1086,22 +1145,172 @@
|
| }
|
| addrmod2(cond | B26 | L, dst, src);
|
|
|
| - // Eliminate pattern: push(r), pop(r)
|
| - // str(r, MemOperand(sp, 4, NegPreIndex), al)
|
| - // ldr(r, MemOperand(sp, 4, PostIndex), al)
|
| - // Both instructions can be eliminated.
|
| - int pattern_size = 2 * kInstrSize;
|
| - if (FLAG_push_pop_elimination &&
|
| - last_bound_pos_ <= (pc_offset() - pattern_size) &&
|
| - reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
|
| - // Pattern.
|
| - instr_at(pc_ - 1 * kInstrSize) == (kPopRegPattern | dst.code() * B12) &&
|
| - instr_at(pc_ - 2 * kInstrSize) == (kPushRegPattern | dst.code() * B12)) {
|
| - pc_ -= 2 * kInstrSize;
|
| - if (FLAG_print_push_pop_elimination) {
|
| - PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
|
| + // Eliminate pattern: push(ry), pop(rx)
|
| + // str(ry, MemOperand(sp, 4, NegPreIndex), al)
|
| + // ldr(rx, MemOperand(sp, 4, PostIndex), al)
|
| + // Both instructions can be eliminated if ry = rx.
|
| + // If ry != rx, a register copy from ry to rx is inserted
|
| + // after eliminating the push and the pop instructions.
|
| + Instr push_instr = instr_at(pc_ - 2 * kInstrSize);
|
| + Instr pop_instr = instr_at(pc_ - 1 * kInstrSize);
|
| +
|
| + if (can_peephole_optimize(2) &&
|
| + IsPush(push_instr) &&
|
| + IsPop(pop_instr)) {
|
| + if ((pop_instr & kRdMask) != (push_instr & kRdMask)) {
|
| + // For consecutive push and pop on different registers,
|
| + // we delete both the push & pop and insert a register move.
|
| + // push ry, pop rx --> mov rx, ry
|
| + Register reg_pushed, reg_popped;
|
| + reg_pushed = GetRd(push_instr);
|
| + reg_popped = GetRd(pop_instr);
|
| + pc_ -= 2 * kInstrSize;
|
| + // Insert a mov instruction, which is better than a pair of push & pop
|
| + mov(reg_popped, reg_pushed);
|
| + if (FLAG_print_peephole_optimization) {
|
| + PrintF("%x push/pop (diff reg) replaced by a reg move\n", pc_offset());
|
| + }
|
| + } else {
|
| + // For consecutive push and pop on the same register,
|
| + // both the push and the pop can be deleted.
|
| + pc_ -= 2 * kInstrSize;
|
| + if (FLAG_print_peephole_optimization) {
|
| + PrintF("%x push/pop (same reg) eliminated\n", pc_offset());
|
| + }
|
| }
|
| }
|
| +
|
| + if (can_peephole_optimize(2)) {
|
| + Instr str_instr = instr_at(pc_ - 2 * kInstrSize);
|
| + Instr ldr_instr = instr_at(pc_ - 1 * kInstrSize);
|
| +
|
| + if ((IsStrRegFpOffset(str_instr) &&
|
| + IsLdrRegFpOffset(ldr_instr)) ||
|
| + (IsStrRegFpNegOffset(str_instr) &&
|
| + IsLdrRegFpNegOffset(ldr_instr))) {
|
| + if ((ldr_instr & kLdrStrInstrArgumentMask) ==
|
| + (str_instr & kLdrStrInstrArgumentMask)) {
|
| + // Pattern: Ldr/str same fp+offset, same register.
|
| + //
|
| + // The following:
|
| + // str rx, [fp, #-12]
|
| + // ldr rx, [fp, #-12]
|
| + //
|
| + // Becomes:
|
| + // str rx, [fp, #-12]
|
| +
|
| + pc_ -= 1 * kInstrSize;
|
| + if (FLAG_print_peephole_optimization) {
|
| + PrintF("%x str/ldr (fp + same offset), same reg\n", pc_offset());
|
| + }
|
| + } else if ((ldr_instr & kLdrStrOffsetMask) ==
|
| + (str_instr & kLdrStrOffsetMask)) {
|
| + // Pattern: Ldr/str same fp+offset, different register.
|
| + //
|
| + // The following:
|
| + // str rx, [fp, #-12]
|
| + // ldr ry, [fp, #-12]
|
| + //
|
| + // Becomes:
|
| + // str rx, [fp, #-12]
|
| + // mov ry, rx
|
| +
|
| + Register reg_stored, reg_loaded;
|
| + reg_stored = GetRd(str_instr);
|
| + reg_loaded = GetRd(ldr_instr);
|
| + pc_ -= 1 * kInstrSize;
|
| + // Insert a mov instruction, which is better than ldr.
|
| + mov(reg_loaded, reg_stored);
|
| + if (FLAG_print_peephole_optimization) {
|
| + PrintF("%x str/ldr (fp + same offset), diff reg \n", pc_offset());
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (can_peephole_optimize(3)) {
|
| + Instr mem_write_instr = instr_at(pc_ - 3 * kInstrSize);
|
| + Instr ldr_instr = instr_at(pc_ - 2 * kInstrSize);
|
| + Instr mem_read_instr = instr_at(pc_ - 1 * kInstrSize);
|
| + if (IsPush(mem_write_instr) &&
|
| + IsPop(mem_read_instr)) {
|
| + if ((IsLdrRegFpOffset(ldr_instr) ||
|
| + IsLdrRegFpNegOffset(ldr_instr))) {
|
| + if ((mem_write_instr & kRdMask) ==
|
| + (mem_read_instr & kRdMask)) {
|
| + // Pattern: push & pop from/to same register,
|
| + // with a fp+offset ldr in between
|
| + //
|
| + // The following:
|
| + // str rx, [sp, #-4]!
|
| + // ldr rz, [fp, #-24]
|
| + // ldr rx, [sp], #+4
|
| + //
|
| + // Becomes:
|
| + // if(rx == rz)
|
| + // delete all
|
| + // else
|
| + // ldr rz, [fp, #-24]
|
| +
|
| + if ((mem_write_instr & kRdMask) == (ldr_instr & kRdMask)) {
|
| + pc_ -= 3 * kInstrSize;
|
| + } else {
|
| + pc_ -= 3 * kInstrSize;
|
| + // Reinsert back the ldr rz.
|
| + emit(ldr_instr);
|
| + }
|
| + if (FLAG_print_peephole_optimization) {
|
| + PrintF("%x push/pop -dead ldr fp+offset in middle\n", pc_offset());
|
| + }
|
| + } else {
|
| + // Pattern: push & pop from/to different registers
|
| + // with a fp+offset ldr in between
|
| + //
|
| + // The following:
|
| + // str rx, [sp, #-4]!
|
| + // ldr rz, [fp, #-24]
|
| + // ldr ry, [sp], #+4
|
| + //
|
| + // Becomes:
|
| + // if(ry == rz)
|
| + // mov ry, rx;
|
| + // else if(rx != rz)
|
| + // ldr rz, [fp, #-24]
|
| + // mov ry, rx
|
| + // else if((ry != rz) || (rx == rz)) becomes:
|
| + // mov ry, rx
|
| + // ldr rz, [fp, #-24]
|
| +
|
| + Register reg_pushed, reg_popped;
|
| + if ((mem_read_instr & kRdMask) == (ldr_instr & kRdMask)) {
|
| + reg_pushed = GetRd(mem_write_instr);
|
| + reg_popped = GetRd(mem_read_instr);
|
| + pc_ -= 3 * kInstrSize;
|
| + mov(reg_popped, reg_pushed);
|
| + } else if ((mem_write_instr & kRdMask)
|
| + != (ldr_instr & kRdMask)) {
|
| + reg_pushed = GetRd(mem_write_instr);
|
| + reg_popped = GetRd(mem_read_instr);
|
| + pc_ -= 3 * kInstrSize;
|
| + emit(ldr_instr);
|
| + mov(reg_popped, reg_pushed);
|
| + } else if (((mem_read_instr & kRdMask)
|
| + != (ldr_instr & kRdMask)) ||
|
| + ((mem_write_instr & kRdMask)
|
| + == (ldr_instr & kRdMask)) ) {
|
| + reg_pushed = GetRd(mem_write_instr);
|
| + reg_popped = GetRd(mem_read_instr);
|
| + pc_ -= 3 * kInstrSize;
|
| + mov(reg_popped, reg_pushed);
|
| + emit(ldr_instr);
|
| + }
|
| + if (FLAG_print_peephole_optimization) {
|
| + PrintF("%x push/pop (ldr fp+off in middle)\n", pc_offset());
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| }
|
|
|
|
|
| @@ -1111,16 +1320,13 @@
|
| // Eliminate pattern: pop(), push(r)
|
| // add sp, sp, #4 LeaveCC, al; str r, [sp, #-4], al
|
| // -> str r, [sp, 0], al
|
| - int pattern_size = 2 * kInstrSize;
|
| - if (FLAG_push_pop_elimination &&
|
| - last_bound_pos_ <= (pc_offset() - pattern_size) &&
|
| - reloc_info_writer.last_pc() <= (pc_ - pattern_size) &&
|
| + if (can_peephole_optimize(2) &&
|
| // Pattern.
|
| instr_at(pc_ - 1 * kInstrSize) == (kPushRegPattern | src.code() * B12) &&
|
| instr_at(pc_ - 2 * kInstrSize) == kPopInstruction) {
|
| pc_ -= 2 * kInstrSize;
|
| emit(al | B26 | 0 | Offset | sp.code() * B16 | src.code() * B12);
|
| - if (FLAG_print_push_pop_elimination) {
|
| + if (FLAG_print_peephole_optimization) {
|
| PrintF("%x pop()/push(reg) eliminated\n", pc_offset());
|
| }
|
| }
|
| @@ -1162,12 +1368,18 @@
|
| #ifdef CAN_USE_ARMV7_INSTRUCTIONS
|
| addrmod3(cond | B7 | B6 | B4, dst, src);
|
| #else
|
| - ldr(dst, src, cond);
|
| + // Generate two ldr instructions if ldrd is not available.
|
| MemOperand src1(src);
|
| src1.set_offset(src1.offset() + 4);
|
| Register dst1(dst);
|
| - dst1.code_ = dst1.code_ + 1;
|
| - ldr(dst1, src1, cond);
|
| + dst1.set_code(dst1.code() + 1);
|
| + if (dst.is(src.rn())) {
|
| + ldr(dst1, src1, cond);
|
| + ldr(dst, src, cond);
|
| + } else {
|
| + ldr(dst, src, cond);
|
| + ldr(dst1, src1, cond);
|
| + }
|
| #endif
|
| }
|
|
|
| @@ -1177,11 +1389,12 @@
|
| #ifdef CAN_USE_ARMV7_INSTRUCTIONS
|
| addrmod3(cond | B7 | B6 | B5 | B4, src, dst);
|
| #else
|
| - str(src, dst, cond);
|
| + // Generate two str instructions if strd is not available.
|
| MemOperand dst1(dst);
|
| dst1.set_offset(dst1.offset() + 4);
|
| Register src1(src);
|
| - src1.code_ = src1.code_ + 1;
|
| + src1.set_code(src1.code() + 1);
|
| + str(src, dst, cond);
|
| str(src1, dst1, cond);
|
| #endif
|
| }
|
| @@ -1216,26 +1429,6 @@
|
| }
|
|
|
|
|
| -// Semaphore instructions.
|
| -void Assembler::swp(Register dst, Register src, Register base, Condition cond) {
|
| - ASSERT(!dst.is(pc) && !src.is(pc) && !base.is(pc));
|
| - ASSERT(!dst.is(base) && !src.is(base));
|
| - emit(cond | P | base.code()*B16 | dst.code()*B12 |
|
| - B7 | B4 | src.code());
|
| -}
|
| -
|
| -
|
| -void Assembler::swpb(Register dst,
|
| - Register src,
|
| - Register base,
|
| - Condition cond) {
|
| - ASSERT(!dst.is(pc) && !src.is(pc) && !base.is(pc));
|
| - ASSERT(!dst.is(base) && !src.is(base));
|
| - emit(cond | P | B | base.code()*B16 | dst.code()*B12 |
|
| - B7 | B4 | src.code());
|
| -}
|
| -
|
| -
|
| // Exception-generating instructions and debugging support.
|
| void Assembler::stop(const char* msg) {
|
| #ifndef __arm__
|
| @@ -1779,34 +1972,6 @@
|
| }
|
|
|
|
|
| -void Assembler::lea(Register dst,
|
| - const MemOperand& x,
|
| - SBit s,
|
| - Condition cond) {
|
| - int am = x.am_;
|
| - if (!x.rm_.is_valid()) {
|
| - // Immediate offset.
|
| - if ((am & P) == 0) // post indexing
|
| - mov(dst, Operand(x.rn_), s, cond);
|
| - else if ((am & U) == 0) // negative indexing
|
| - sub(dst, x.rn_, Operand(x.offset_), s, cond);
|
| - else
|
| - add(dst, x.rn_, Operand(x.offset_), s, cond);
|
| - } else {
|
| - // Register offset (shift_imm_ and shift_op_ are 0) or scaled
|
| - // register offset the constructors make sure than both shift_imm_
|
| - // and shift_op_ are initialized.
|
| - ASSERT(!x.rm_.is(pc));
|
| - if ((am & P) == 0) // post indexing
|
| - mov(dst, Operand(x.rn_), s, cond);
|
| - else if ((am & U) == 0) // negative indexing
|
| - sub(dst, x.rn_, Operand(x.rm_, x.shift_op_, x.shift_imm_), s, cond);
|
| - else
|
| - add(dst, x.rn_, Operand(x.rm_, x.shift_op_, x.shift_imm_), s, cond);
|
| - }
|
| -}
|
| -
|
| -
|
| bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
|
| uint32_t dummy1;
|
| uint32_t dummy2;
|
| @@ -2062,3 +2227,5 @@
|
|
|
|
|
| } } // namespace v8::internal
|
| +
|
| +#endif // V8_TARGET_ARCH_ARM
|
|
|