Commit 6de39cd1 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

ARM: Add Ldrd/Strd to the macro assembler

The macro assembler now checks for ARMv7 support and generates instructions for Ldrd/Strd accordingly. INstructions ldrd/strd in the assembler requires ARMv7 support enabled. This removes the a check for CAN_USE_ARMV7_INSTRUCTIONS making the ARMv7 support in the simulator fully controled by the --enable-armv7 flag.
Review URL: http://codereview.chromium.org/2226003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4726 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4afc3d3c
......@@ -1363,46 +1363,25 @@ void Assembler::ldrsh(Register dst, const MemOperand& src, Condition cond) {
}
void Assembler::ldrd(Register dst1,
Register dst2,
void Assembler::ldrd(Register dst1, Register dst2,
const MemOperand& src, Condition cond) {
ASSERT(CpuFeatures::IsEnabled(ARMv7));
ASSERT(src.rm().is(no_reg));
ASSERT(!dst1.is(lr)); // r14.
ASSERT_EQ(0, dst1.code() % 2);
ASSERT_EQ(dst1.code() + 1, dst2.code());
#ifdef CAN_USE_ARMV7_INSTRUCTIONS
addrmod3(cond | B7 | B6 | B4, dst1, src);
#else
// Generate two ldr instructions if ldrd is not available.
MemOperand src2(src);
src2.set_offset(src2.offset() + 4);
if (dst1.is(src.rn())) {
ldr(dst2, src2, cond);
ldr(dst1, src, cond);
} else {
ldr(dst1, src, cond);
ldr(dst2, src2, cond);
}
#endif
}
void Assembler::strd(Register src1,
Register src2,
void Assembler::strd(Register src1, Register src2,
const MemOperand& dst, Condition cond) {
ASSERT(dst.rm().is(no_reg));
ASSERT(!src1.is(lr)); // r14.
ASSERT_EQ(0, src1.code() % 2);
ASSERT_EQ(src1.code() + 1, src2.code());
#ifdef CAN_USE_ARMV7_INSTRUCTIONS
ASSERT(CpuFeatures::IsEnabled(ARMv7));
addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
#else
// Generate two str instructions if strd is not available.
MemOperand dst2(dst);
dst2.set_offset(dst2.offset() + 4);
str(src1, dst, cond);
str(src2, dst2, cond);
#endif
}
// Load/Store multiple instructions.
......
......@@ -1514,7 +1514,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));
__ strd(r0, r1, MemOperand(sp, 2 * kPointerSize));
__ Strd(r0, r1, MemOperand(sp, 2 * kPointerSize));
CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS);
frame_->CallStub(&call_function, 3);
......@@ -2307,7 +2307,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
node->continue_target()->SetExpectedHeight();
// Load the current count to r0, load the length to r1.
__ ldrd(r0, r1, frame_->ElementAt(0));
__ Ldrd(r0, r1, frame_->ElementAt(0));
__ cmp(r0, r1); // compare to the array length
node->break_target()->Branch(hs);
......@@ -6379,7 +6379,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.
__ ldrd(r0, r1, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ Ldrd(r0, r1, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ pop(lr);
}
......@@ -6414,7 +6414,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
} else {
__ push(lr);
// Load lhs to a double in r2, r3.
__ ldrd(r2, r3, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ Ldrd(r2, r3, FieldMemOperand(r1, HeapNumber::kValueOffset));
// Convert rhs to a double in r0, r1.
__ mov(r7, Operand(r0));
ConvertToDoubleStub stub2(r1, r0, r7, r6);
......@@ -6578,8 +6578,8 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
__ sub(r7, r1, Operand(kHeapObjectTag));
__ vldr(d7, r7, HeapNumber::kValueOffset);
} else {
__ ldrd(r2, r3, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ ldrd(r0, r1, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ Ldrd(r2, r3, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ Ldrd(r0, r1, FieldMemOperand(r0, HeapNumber::kValueOffset));
}
__ jmp(both_loaded_as_doubles);
}
......@@ -6956,7 +6956,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ vldr(d7, r7, HeapNumber::kValueOffset);
} else {
// Calling convention says that second double is in r2 and r3.
__ ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
__ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
}
__ jmp(&finished_loading_r0);
__ bind(&r0_is_smi);
......@@ -7008,7 +7008,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ vldr(d6, r7, HeapNumber::kValueOffset);
} else {
// Calling convention says that first double is in r0 and r1.
__ ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
__ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
}
__ jmp(&finished_loading_r1);
__ bind(&r1_is_smi);
......@@ -7079,7 +7079,7 @@ void GenericBinaryOpStub::HandleBinaryOpSlowCases(
__ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
#else
// Double returned in registers 0 and 1.
__ strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset));
__ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset));
#endif
__ mov(r0, Operand(r5));
// And we are done.
......
......@@ -935,7 +935,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for doing the condition check.
__ bind(&loop);
// Load the current count to r0, load the length to r1.
__ ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
__ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
__ cmp(r0, r1); // Compare to the array length.
__ b(hs, loop_statement.break_target());
......
......@@ -354,6 +354,51 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
}
void MacroAssembler::Ldrd(Register dst1, Register dst2,
const MemOperand& src, Condition cond) {
ASSERT(src.rm().is(no_reg));
ASSERT(!dst1.is(lr)); // r14.
ASSERT_EQ(0, dst1.code() % 2);
ASSERT_EQ(dst1.code() + 1, dst2.code());
// Generate two ldr instructions if ldrd is not available.
if (CpuFeatures::IsSupported(ARMv7)) {
CpuFeatures::Scope scope(ARMv7);
ldrd(dst1, dst2, src, cond);
} else {
MemOperand src2(src);
src2.set_offset(src2.offset() + 4);
if (dst1.is(src.rn())) {
ldr(dst2, src2, cond);
ldr(dst1, src, cond);
} else {
ldr(dst1, src, cond);
ldr(dst2, src2, cond);
}
}
}
void MacroAssembler::Strd(Register src1, Register src2,
const MemOperand& dst, Condition cond) {
ASSERT(dst.rm().is(no_reg));
ASSERT(!src1.is(lr)); // r14.
ASSERT_EQ(0, src1.code() % 2);
ASSERT_EQ(src1.code() + 1, src2.code());
// Generate two str instructions if strd is not available.
if (CpuFeatures::IsSupported(ARMv7)) {
CpuFeatures::Scope scope(ARMv7);
strd(src1, src2, dst, cond);
} else {
MemOperand dst2(dst);
dst2.set_offset(dst2.offset() + 4);
str(src1, dst, cond);
str(src2, dst2, cond);
}
}
void MacroAssembler::EnterFrame(StackFrame::Type type) {
// r0-r3: preserved
stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
......
......@@ -185,6 +185,18 @@ class MacroAssembler: public Assembler {
}
}
// Load two consecutive registers with two consecutive memory locations.
void Ldrd(Register dst1,
Register dst2,
const MemOperand& src,
Condition cond = al);
// Store two consecutive registers to two consecutive memory locations.
void Strd(Register src1,
Register src2,
const MemOperand& dst,
Condition cond = al);
// ---------------------------------------------------------------------------
// Stack limit support
......
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