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 |