Commit d5738c0e authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Add ldrd and strd instructions to the ARM port. This is a

commit for zhangk@codeaurora.org.  See
http://codereview.chromium.org/568029 and
http://codereview.chromium.org/2019003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4618 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ae4cc3c2
...@@ -18,6 +18,7 @@ Jan de Mooij <jandemooij@gmail.com> ...@@ -18,6 +18,7 @@ Jan de Mooij <jandemooij@gmail.com>
Jay Freeman <saurik@saurik.com> Jay Freeman <saurik@saurik.com>
Joel Stanley <joel.stan@gmail.com> Joel Stanley <joel.stan@gmail.com>
John Jozwiak <jjozwiak@codeaurora.org> John Jozwiak <jjozwiak@codeaurora.org>
Kun Zhang <zhangk@codeaurora.org>
Matt Hanselman <mjhanselman@gmail.com> Matt Hanselman <mjhanselman@gmail.com>
Martyn Capewell <martyn.capewell@arm.com> Martyn Capewell <martyn.capewell@arm.com>
Paolo Giarrusso <p.giarrusso@gmail.com> Paolo Giarrusso <p.giarrusso@gmail.com>
......
...@@ -1157,6 +1157,35 @@ void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) { ...@@ -1157,6 +1157,35 @@ void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
} }
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. // Load/Store multiple instructions.
void Assembler::ldm(BlockAddrMode am, void Assembler::ldm(BlockAddrMode am,
Register base, Register base,
......
...@@ -448,6 +448,18 @@ class MemOperand BASE_EMBEDDED { ...@@ -448,6 +448,18 @@ class MemOperand BASE_EMBEDDED {
explicit MemOperand(Register rn, Register rm, explicit MemOperand(Register rn, Register rm,
ShiftOp shift_op, int shift_imm, AddrMode am = Offset); 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: private:
Register rn_; // base Register rn_; // base
Register rm_; // register offset Register rm_; // register offset
...@@ -755,6 +767,8 @@ class Assembler : public Malloced { ...@@ -755,6 +767,8 @@ class Assembler : public Malloced {
void strh(Register src, const MemOperand& dst, Condition cond = al); void strh(Register src, const MemOperand& dst, Condition cond = al);
void ldrsb(Register dst, const MemOperand& src, Condition cond = al); void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
void ldrsh(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 // Load/Store multiple instructions
void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al); void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
......
...@@ -1486,8 +1486,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, ...@@ -1486,8 +1486,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
// Then process it as a normal function call. // Then process it as a normal function call.
__ ldr(r0, MemOperand(sp, 3 * kPointerSize)); __ ldr(r0, MemOperand(sp, 3 * kPointerSize));
__ ldr(r1, MemOperand(sp, 2 * kPointerSize)); __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
__ str(r0, MemOperand(sp, 2 * kPointerSize)); __ strd(r0, MemOperand(sp, 2 * kPointerSize));
__ str(r1, MemOperand(sp, 3 * kPointerSize));
CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS); CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS);
frame_->CallStub(&call_function, 3); frame_->CallStub(&call_function, 3);
...@@ -2279,8 +2278,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { ...@@ -2279,8 +2278,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
__ ldr(r0, frame_->ElementAt(0)); // load the current count // Load the current count to r0, load the length to r1.
__ ldr(r1, frame_->ElementAt(1)); // load the length __ ldrd(r0, frame_->ElementAt(0));
__ cmp(r0, r1); // compare to the array length __ cmp(r0, r1); // compare to the array length
node->break_target()->Branch(hs); node->break_target()->Branch(hs);
...@@ -6310,8 +6309,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, ...@@ -6310,8 +6309,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
ConvertToDoubleStub stub1(r3, r2, r7, r6); ConvertToDoubleStub stub1(r3, r2, r7, r6);
__ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
// Load rhs to a double in r0, r1. // Load rhs to a double in r0, r1.
__ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize)); __ ldrd(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ pop(lr); __ pop(lr);
} }
...@@ -6346,8 +6344,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, ...@@ -6346,8 +6344,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
} else { } else {
__ push(lr); __ push(lr);
// Load lhs to a double in r2, r3. // Load lhs to a double in r2, r3.
__ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); __ ldrd(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
// Convert rhs to a double in r0, r1. // Convert rhs to a double in r0, r1.
__ mov(r7, Operand(r0)); __ mov(r7, Operand(r0));
ConvertToDoubleStub stub2(r1, r0, r7, r6); ConvertToDoubleStub stub2(r1, r0, r7, r6);
...@@ -6511,10 +6508,8 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, ...@@ -6511,10 +6508,8 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
__ sub(r7, r1, Operand(kHeapObjectTag)); __ sub(r7, r1, Operand(kHeapObjectTag));
__ vldr(d7, r7, HeapNumber::kValueOffset); __ vldr(d7, r7, HeapNumber::kValueOffset);
} else { } else {
__ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset)); __ ldrd(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); __ ldrd(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
__ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
} }
__ jmp(both_loaded_as_doubles); __ jmp(both_loaded_as_doubles);
} }
...@@ -6891,8 +6886,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( ...@@ -6891,8 +6886,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ vldr(d7, r7, HeapNumber::kValueOffset); __ vldr(d7, r7, HeapNumber::kValueOffset);
} else { } else {
// Calling convention says that second double is in r2 and r3. // Calling convention says that second double is in r2 and r3.
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kValueOffset)); __ ldrd(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ ldr(r3, FieldMemOperand(r0, HeapNumber::kValueOffset + 4));
} }
__ jmp(&finished_loading_r0); __ jmp(&finished_loading_r0);
__ bind(&r0_is_smi); __ bind(&r0_is_smi);
...@@ -6944,8 +6938,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( ...@@ -6944,8 +6938,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ vldr(d6, r7, HeapNumber::kValueOffset); __ vldr(d6, r7, HeapNumber::kValueOffset);
} else { } else {
// Calling convention says that first double is in r0 and r1. // Calling convention says that first double is in r0 and r1.
__ ldr(r0, FieldMemOperand(r1, HeapNumber::kValueOffset)); __ ldrd(r0, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ ldr(r1, FieldMemOperand(r1, HeapNumber::kValueOffset + 4));
} }
__ jmp(&finished_loading_r1); __ jmp(&finished_loading_r1);
__ bind(&r1_is_smi); __ bind(&r1_is_smi);
...@@ -7016,8 +7009,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( ...@@ -7016,8 +7009,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset)); __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
#else #else
// Double returned in registers 0 and 1. // Double returned in registers 0 and 1.
__ str(r0, FieldMemOperand(r5, HeapNumber::kValueOffset)); __ strd(r0, FieldMemOperand(r5, HeapNumber::kValueOffset));
__ str(r1, FieldMemOperand(r5, HeapNumber::kValueOffset + 4));
#endif #endif
__ mov(r0, Operand(r5)); __ mov(r0, Operand(r5));
// And we are done. // And we are done.
......
...@@ -418,6 +418,12 @@ int Decoder::FormatOption(Instr* instr, const char* format) { ...@@ -418,6 +418,12 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
ASSERT(STRING_STARTS_WITH(format, "memop")); ASSERT(STRING_STARTS_WITH(format, "memop"));
if (instr->HasL()) { if (instr->HasL()) {
Print("ldr"); 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 { } else {
Print("str"); Print("str");
} }
...@@ -614,6 +620,47 @@ void Decoder::DecodeType01(Instr* instr) { ...@@ -614,6 +620,47 @@ void Decoder::DecodeType01(Instr* instr) {
} else { } else {
Unknown(instr); // not used by V8 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 { } else {
// extra load/store instructions // extra load/store instructions
switch (instr->PUField()) { switch (instr->PUField()) {
......
...@@ -728,6 +728,13 @@ int32_t Simulator::get_register(int reg) const { ...@@ -728,6 +728,13 @@ int32_t Simulator::get_register(int reg) const {
} }
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. // Raw access to the PC register.
void Simulator::set_pc(int32_t value) { void Simulator::set_pc(int32_t value) {
pc_modified_ = true; pc_modified_ = true;
...@@ -887,7 +894,7 @@ int Simulator::ReadW(int32_t addr, Instr* instr) { ...@@ -887,7 +894,7 @@ int Simulator::ReadW(int32_t addr, Instr* instr) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
return *ptr; return *ptr;
} }
PrintF("Unaligned read at 0x%08x\n", addr); PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
UNIMPLEMENTED(); UNIMPLEMENTED();
return 0; return 0;
#endif #endif
...@@ -1001,6 +1008,41 @@ void Simulator::WriteB(int32_t addr, int8_t value) { ...@@ -1001,6 +1008,41 @@ void Simulator::WriteB(int32_t addr, int8_t 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. // Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit() const { uintptr_t Simulator::StackLimit() const {
// Leave a safety margin of 256 bytes to prevent overrunning the stack when // Leave a safety margin of 256 bytes to prevent overrunning the stack when
...@@ -1628,7 +1670,19 @@ void Simulator::DecodeType01(Instr* instr) { ...@@ -1628,7 +1670,19 @@ void Simulator::DecodeType01(Instr* instr) {
} }
} }
} }
if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
ASSERT((rd % 2) == 0);
if (instr->HasH()) { 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->HasSign()) {
if (instr->HasL()) { if (instr->HasL()) {
int16_t val = ReadH(addr, instr); int16_t val = ReadH(addr, instr);
......
...@@ -159,6 +159,7 @@ class Simulator { ...@@ -159,6 +159,7 @@ class Simulator {
// instruction. // instruction.
void set_register(int reg, int32_t value); void set_register(int reg, int32_t value);
int32_t get_register(int reg) const; int32_t get_register(int reg) const;
void set_dw_register(int dreg, const int* dbl);
// Support for VFP. // Support for VFP.
void set_s_register(int reg, unsigned int value); void set_s_register(int reg, unsigned int value);
...@@ -252,6 +253,9 @@ class Simulator { ...@@ -252,6 +253,9 @@ class Simulator {
inline int ReadW(int32_t addr, Instr* instr); inline int ReadW(int32_t addr, Instr* instr);
inline void WriteW(int32_t addr, int value, 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. // Executing is handled based on the instruction type.
void DecodeType01(Instr* instr); // both type 0 and type 1 rolled into one void DecodeType01(Instr* instr); // both type 0 and type 1 rolled into one
void DecodeType2(Instr* instr); void DecodeType2(Instr* instr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment