Revision: 4618
Author: [email protected]
Date: Fri May 7 13:02:57 2010
Log: Add ldrd and strd instructions to the ARM port. This is a
commit for [email protected]. See
http://codereview.chromium.org/568029 and
http://codereview.chromium.org/2019003
http://code.google.com/p/v8/source/detail?r=4618
Modified:
/branches/bleeding_edge/AUTHORS
/branches/bleeding_edge/src/arm/assembler-arm.cc
/branches/bleeding_edge/src/arm/assembler-arm.h
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/disasm-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.h
=======================================
--- /branches/bleeding_edge/AUTHORS Thu Apr 22 10:28:43 2010
+++ /branches/bleeding_edge/AUTHORS Fri May 7 13:02:57 2010
@@ -18,6 +18,7 @@
Jay Freeman <[email protected]>
Joel Stanley <[email protected]>
John Jozwiak <[email protected]>
+Kun Zhang <[email protected]>
Matt Hanselman <[email protected]>
Martyn Capewell <[email protected]>
Paolo Giarrusso <[email protected]>
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Apr 27 04:16:05
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Fri May 7 13:02:57
2010
@@ -1157,6 +1157,35 @@
}
+void Assembler::ldrd(Register dst, const MemOperand& src, Condition cond) {
+ ASSERT(src.rm().is(no_reg));
+#ifdef CAN_USE_ARMV7_INSTRUCTIONS
+ addrmod3(cond | B7 | B6 | B4, dst, src);
+#else
+ ldr(dst, src, cond);
+ MemOperand src1(src);
+ src1.set_offset(src1.offset() + 4);
+ Register dst1(dst);
+ dst1.code_ = dst1.code_ + 1;
+ ldr(dst1, src1, cond);
+#endif
+}
+
+
+void Assembler::strd(Register src, const MemOperand& dst, Condition cond) {
+ ASSERT(dst.rm().is(no_reg));
+#ifdef CAN_USE_ARMV7_INSTRUCTIONS
+ addrmod3(cond | B7 | B6 | B5 | B4, src, dst);
+#else
+ str(src, dst, cond);
+ MemOperand dst1(dst);
+ dst1.set_offset(dst1.offset() + 4);
+ Register src1(src);
+ src1.code_ = src1.code_ + 1;
+ str(src1, dst1, cond);
+#endif
+}
+
// Load/Store multiple instructions.
void Assembler::ldm(BlockAddrMode am,
Register base,
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Tue Apr 27 02:09:51 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Fri May 7 13:02:57 2010
@@ -448,6 +448,18 @@
explicit MemOperand(Register rn, Register rm,
ShiftOp shift_op, int shift_imm, AddrMode am =
Offset);
+ void set_offset(int32_t offset) {
+ ASSERT(rm_.is(no_reg));
+ offset_ = offset;
+ }
+
+ uint32_t offset() {
+ ASSERT(rm_.is(no_reg));
+ return offset_;
+ }
+
+ Register rm() const {return rm_;}
+
private:
Register rn_; // base
Register rm_; // register offset
@@ -755,6 +767,8 @@
void strh(Register src, const MemOperand& dst, Condition cond = al);
void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
+ void ldrd(Register dst, const MemOperand& src, Condition cond = al);
+ void strd(Register src, const MemOperand& dst, Condition cond = al);
// Load/Store multiple instructions
void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond =
al);
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Fri May 7 07:06:55 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Fri May 7 13:02:57 2010
@@ -1486,8 +1486,7 @@
// Then process it as a normal function call.
__ ldr(r0, MemOperand(sp, 3 * kPointerSize));
__ ldr(r1, MemOperand(sp, 2 * kPointerSize));
- __ str(r0, MemOperand(sp, 2 * kPointerSize));
- __ str(r1, MemOperand(sp, 3 * kPointerSize));
+ __ strd(r0, MemOperand(sp, 2 * kPointerSize));
CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS);
frame_->CallStub(&call_function, 3);
@@ -2279,8 +2278,8 @@
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
- __ ldr(r0, frame_->ElementAt(0)); // load the current count
- __ ldr(r1, frame_->ElementAt(1)); // load the length
+ // Load the current count to r0, load the length to r1.
+ __ ldrd(r0, frame_->ElementAt(0));
__ cmp(r0, r1); // compare to the array length
node->break_target()->Branch(hs);
@@ -6310,8 +6309,7 @@
ConvertToDoubleStub stub1(r3, r2, r7, r6);
__ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
// Load rhs to a double in r0, r1.
- __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset +
kPointerSize));
- __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+ __ ldrd(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ pop(lr);
}
@@ -6346,8 +6344,7 @@
} else {
__ push(lr);
// Load lhs to a double in r2, r3.
- __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset +
kPointerSize));
- __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
+ __ ldrd(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
// Convert rhs to a double in r0, r1.
__ mov(r7, Operand(r0));
ConvertToDoubleStub stub2(r1, r0, r7, r6);
@@ -6511,10 +6508,8 @@
__ sub(r7, r1, Operand(kHeapObjectTag));
__ vldr(d7, r7, HeapNumber::kValueOffset);
} else {
- __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
- __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset +
kPointerSize));
- __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset +
kPointerSize));
- __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+ __ ldrd(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
+ __ ldrd(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
}
__ jmp(both_loaded_as_doubles);
}
@@ -6891,8 +6886,7 @@
__ vldr(d7, r7, HeapNumber::kValueOffset);
} else {
// Calling convention says that second double is in r2 and r3.
- __ ldr(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
- __ ldr(r3, FieldMemOperand(r0, HeapNumber::kValueOffset + 4));
+ __ ldrd(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
}
__ jmp(&finished_loading_r0);
__ bind(&r0_is_smi);
@@ -6944,8 +6938,7 @@
__ vldr(d6, r7, HeapNumber::kValueOffset);
} else {
// Calling convention says that first double is in r0 and r1.
- __ ldr(r0, FieldMemOperand(r1, HeapNumber::kValueOffset));
- __ ldr(r1, FieldMemOperand(r1, HeapNumber::kValueOffset + 4));
+ __ ldrd(r0, FieldMemOperand(r1, HeapNumber::kValueOffset));
}
__ jmp(&finished_loading_r1);
__ bind(&r1_is_smi);
@@ -7016,8 +7009,7 @@
__ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
#else
// Double returned in registers 0 and 1.
- __ str(r0, FieldMemOperand(r5, HeapNumber::kValueOffset));
- __ str(r1, FieldMemOperand(r5, HeapNumber::kValueOffset + 4));
+ __ strd(r0, FieldMemOperand(r5, HeapNumber::kValueOffset));
#endif
__ mov(r0, Operand(r5));
// And we are done.
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc Wed Apr 21 02:45:06 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc Fri May 7 13:02:57 2010
@@ -418,6 +418,12 @@
ASSERT(STRING_STARTS_WITH(format, "memop"));
if (instr->HasL()) {
Print("ldr");
+ } else if ((instr->Bits(27, 25) == 0) && (instr->Bit(20) == 0)) {
+ if (instr->Bits(7, 4) == 0xf) {
+ Print("strd");
+ } else {
+ Print("ldrd");
+ }
} else {
Print("str");
}
@@ -614,6 +620,47 @@
} else {
Unknown(instr); // not used by V8
}
+ } else if ((instr->Bit(20) == 0) && ((instr->Bits(7, 4) & 0xd) ==
0xd)) {
+ // ldrd, strd
+ switch (instr->PUField()) {
+ case 0: {
+ if (instr->Bit(22) == 0) {
+ Format(instr, "'memop'cond's 'rd, ['rn], -'rm");
+ } else {
+ Format(instr, "'memop'cond's 'rd, ['rn], #-'off8");
+ }
+ break;
+ }
+ case 1: {
+ if (instr->Bit(22) == 0) {
+ Format(instr, "'memop'cond's 'rd, ['rn], +'rm");
+ } else {
+ Format(instr, "'memop'cond's 'rd, ['rn], #+'off8");
+ }
+ break;
+ }
+ case 2: {
+ if (instr->Bit(22) == 0) {
+ Format(instr, "'memop'cond's 'rd, ['rn, -'rm]'w");
+ } else {
+ Format(instr, "'memop'cond's 'rd, ['rn, #-'off8]'w");
+ }
+ break;
+ }
+ case 3: {
+ if (instr->Bit(22) == 0) {
+ Format(instr, "'memop'cond's 'rd, ['rn, +'rm]'w");
+ } else {
+ Format(instr, "'memop'cond's 'rd, ['rn, #+'off8]'w");
+ }
+ break;
+ }
+ default: {
+ // The PU field is a 2-bit field.
+ UNREACHABLE();
+ break;
+ }
+ }
} else {
// extra load/store instructions
switch (instr->PUField()) {
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Thu May 6 05:49:12
2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Fri May 7 13:02:57
2010
@@ -726,6 +726,13 @@
ASSERT((reg >= 0) && (reg < num_registers));
return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0);
}
+
+
+void Simulator::set_dw_register(int dreg, const int* dbl) {
+ ASSERT((dreg >= 0) && (dreg < num_d_registers));
+ registers_[dreg] = dbl[0];
+ registers_[dreg + 1] = dbl[1];
+}
// Raw access to the PC register.
@@ -887,7 +894,7 @@
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
return *ptr;
}
- PrintF("Unaligned read at 0x%08x\n", addr);
+ PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
UNIMPLEMENTED();
return 0;
#endif
@@ -999,6 +1006,41 @@
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
*ptr = value;
}
+
+
+int32_t* Simulator::ReadDW(int32_t addr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+ return ptr;
+#else
+ if ((addr & 3) == 0) {
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+ return ptr;
+ }
+ PrintF("Unaligned read at 0x%08x\n", addr);
+ UNIMPLEMENTED();
+ return 0;
+#endif
+}
+
+
+void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+ *ptr++ = value1;
+ *ptr = value2;
+ return;
+#else
+ if ((addr & 3) == 0) {
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+ *ptr++ = value1;
+ *ptr = value2;
+ return;
+ }
+ PrintF("Unaligned write at 0x%08x\n", addr);
+ UNIMPLEMENTED();
+#endif
+}
// Returns the limit of the stack area to enable checking for stack
overflows.
@@ -1628,7 +1670,19 @@
}
}
}
- if (instr->HasH()) {
+ if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
+ ASSERT((rd % 2) == 0);
+ if (instr->HasH()) {
+ // The strd instruction.
+ int32_t value1 = get_register(rd);
+ int32_t value2 = get_register(rd+1);
+ WriteDW(addr, value1, value2);
+ } else {
+ // The ldrd instruction.
+ int* rn_data = ReadDW(addr);
+ set_dw_register(rd, rn_data);
+ }
+ } else if (instr->HasH()) {
if (instr->HasSign()) {
if (instr->HasL()) {
int16_t val = ReadH(addr, instr);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.h Thu Apr 22 05:41:10 2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.h Fri May 7 13:02:57 2010
@@ -159,6 +159,7 @@
// instruction.
void set_register(int reg, int32_t value);
int32_t get_register(int reg) const;
+ void set_dw_register(int dreg, const int* dbl);
// Support for VFP.
void set_s_register(int reg, unsigned int value);
@@ -252,6 +253,9 @@
inline int ReadW(int32_t addr, Instr* instr);
inline void WriteW(int32_t addr, int value, Instr* instr);
+ int32_t* ReadDW(int32_t addr);
+ void WriteDW(int32_t addr, int32_t value1, int32_t value2);
+
// Executing is handled based on the instruction type.
void DecodeType01(Instr* instr); // both type 0 and type 1 rolled into
one
void DecodeType2(Instr* instr);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev