diff --git a/AUTHORS b/AUTHORS index be34cd4f3e..7e8f1f8d52 100644 --- a/AUTHORS +++ b/AUTHORS @@ -18,6 +18,7 @@ Jan de Mooij Jay Freeman Joel Stanley John Jozwiak +Kun Zhang Matt Hanselman Martyn Capewell Paolo Giarrusso diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 7990368e66..f1f59ced7f 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -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. void Assembler::ldm(BlockAddrMode am, Register base, diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 839ed67375..61b84d434f 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -448,6 +448,18 @@ class MemOperand BASE_EMBEDDED { 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 @@ class Assembler : public Malloced { 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); diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index d7be16e669..5509830b30 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -1486,8 +1486,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, // 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 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { 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 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, 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 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, } 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 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, __ 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 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ 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 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ 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 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases( __ 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. diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index 4ba309467b..4051096fca 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -418,6 +418,12 @@ int Decoder::FormatOption(Instr* instr, const char* format) { 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 @@ void Decoder::DecodeType01(Instr* instr) { } 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()) { diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index 95827a700c..e4601f3e3f 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -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. void Simulator::set_pc(int32_t value) { pc_modified_ = true; @@ -887,7 +894,7 @@ int Simulator::ReadW(int32_t addr, Instr* instr) { intptr_t* ptr = reinterpret_cast(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 @@ -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(addr); + return ptr; +#else + if ((addr & 3) == 0) { + int32_t* ptr = reinterpret_cast(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(addr); + *ptr++ = value1; + *ptr = value2; + return; +#else + if ((addr & 3) == 0) { + int32_t* ptr = reinterpret_cast(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. uintptr_t Simulator::StackLimit() const { // Leave a safety margin of 256 bytes to prevent overrunning the stack when @@ -1628,7 +1670,19 @@ void Simulator::DecodeType01(Instr* instr) { } } } - 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); diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h index 91614ea2d7..61af3aa6e0 100644 --- a/src/arm/simulator-arm.h +++ b/src/arm/simulator-arm.h @@ -159,6 +159,7 @@ class Simulator { // 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 @@ class Simulator { 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);