Commit 8198db79 authored by ager@chromium.org's avatar ager@chromium.org

ARM: Add support for DoMathAbs with double inputs.

Adds vabs instruction to simulator, assembler, disassembler and tests.

BUG=none
TEST=Added to cctest.

Review URL: http://codereview.chromium.org/6366016

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6531 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0a9004aa
......@@ -2228,6 +2228,14 @@ void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
}
void Assembler::vabs(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond) {
emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 |
0x5*B9 | B8 | 0x3*B6 | src.code());
}
void Assembler::vadd(const DwVfpRegister dst,
const DwVfpRegister src1,
const DwVfpRegister src2,
......
......@@ -975,6 +975,9 @@ class Assembler : public Malloced {
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vabs(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond = al);
void vadd(const DwVfpRegister dst,
const DwVfpRegister src1,
const DwVfpRegister src2,
......
......@@ -1064,6 +1064,9 @@ void Decoder::DecodeTypeVFP(Instruction* instr) {
} else {
Format(instr, "vmov.f32'cond 'Sd, 'Sm");
}
} else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
// vabs
Format(instr, "vabs'cond 'Dd, 'Dm");
} else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
} else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
......
......@@ -1174,8 +1174,7 @@ void LCodeGen::DoDeferredGenericBinaryStub(LTemplateInstruction<1, 2, T>* instr,
0,
Safepoint::kNoDeoptimizationIndex);
// Overwrite the stored value of r0 with the result of the stub.
__ str(r0, MemOperand(sp, DwVfpRegister::kNumAllocatableRegisters *
kDoubleSize));
__ StoreToSafepointRegistersAndDoublesSlot(r0);
__ PopSafepointRegistersAndDoubles();
}
......@@ -2525,6 +2524,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
ASSERT(instr->InputAt(0)->Equals(instr->result()));
Register input = ToRegister(instr->InputAt(0));
Register scratch = scratch0();
......@@ -2535,28 +2535,32 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
DeoptimizeIf(ne, instr->environment());
Label done;
Label negative;
__ ldr(scratch, FieldMemOperand(input, HeapNumber::kExponentOffset));
Register exponent = scratch0();
scratch = no_reg;
__ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
// Check the sign of the argument. If the argument is positive, just
// return it. We do not need to patch the stack since |input| and
// |result| are the same register and |input| will be restored
// |result| are the same register and |input| would be restored
// unchanged by popping safepoint registers.
__ tst(scratch, Operand(HeapNumber::kSignMask));
__ b(ne, &negative);
__ jmp(&done);
__ tst(exponent, Operand(HeapNumber::kSignMask));
__ b(eq, &done);
__ bind(&negative);
// Input is negative. Reverse its sign.
// Preserve the value of all registers.
__ PushSafepointRegisters();
Register tmp = input.is(r0) ? r1 : r0;
Register tmp2 = input.is(r2) ? r3 : r2;
Register tmp3 = input.is(r4) ? r5 : r4;
// Registers were saved at the safepoint, so we can use
// many scratch registers.
Register tmp1 = input.is(r1) ? r0 : r1;
Register tmp2 = input.is(r2) ? r0 : r2;
Register tmp3 = input.is(r3) ? r0 : r3;
Register tmp4 = input.is(r4) ? r0 : r4;
// exponent: floating point exponent value.
Label allocated, slow;
__ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(tmp, tmp2, tmp3, scratch, &slow);
__ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
__ b(&allocated);
// Slow case: Call the runtime system to do the number allocation.
......@@ -2566,20 +2570,20 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
RecordSafepointWithRegisters(
instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
// Set the pointer to the new heap number in tmp.
if (!tmp.is(r0)) __ mov(tmp, Operand(r0));
if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0));
// Restore input_reg after call to runtime.
MemOperand input_register_slot = masm()->SafepointRegisterSlot(input);
__ ldr(input, input_register_slot);
__ LoadFromSafepointRegisterSlot(input);
__ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
__ bind(&allocated);
__ ldr(tmp2, FieldMemOperand(input, HeapNumber::kExponentOffset));
__ bic(tmp2, tmp2, Operand(HeapNumber::kSignMask));
__ str(tmp2, FieldMemOperand(tmp, HeapNumber::kExponentOffset));
// exponent: floating point exponent value.
// tmp1: allocated heap number.
__ bic(exponent, exponent, Operand(HeapNumber::kSignMask));
__ str(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
__ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
__ str(tmp2, FieldMemOperand(tmp, HeapNumber::kMantissaOffset));
__ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
__ str(tmp, input_register_slot);
__ str(tmp1, masm()->SafepointRegisterSlot(input));
__ PopSafepointRegisters();
__ bind(&done);
......@@ -2587,15 +2591,14 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
Label is_positive;
uint32_t kSignMask = 0x80000000u;
Register input = ToRegister(instr->InputAt(0));
__ tst(input, Operand(kSignMask));
__ b(eq, &is_positive);
__ rsb(input, input, Operand(0), SetCC);
__ cmp(input, Operand(0));
// We can make rsb conditional because the previous cmp instruction
// will clear the V (overflow) flag and rsb won't set this flag
// if input is positive.
__ rsb(input, input, Operand(0), SetCC, mi);
// Deoptimize on overflow.
DeoptimizeIf(vs, instr->environment());
__ bind(&is_positive);
}
......@@ -2617,8 +2620,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
Representation r = instr->hydrogen()->value()->representation();
if (r.IsDouble()) {
DwVfpRegister input = ToDoubleRegister(instr->InputAt(0));
// __ vabs(input, input);
Abort("Double DoMathAbs unimplemented");
__ vabs(input, input);
} else if (r.IsInteger32()) {
EmitIntegerMathAbs(instr);
} else {
......
......@@ -485,11 +485,21 @@ void MacroAssembler::PopSafepointRegistersAndDoubles() {
PopSafepointRegisters();
}
void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register reg) {
str(reg, SafepointRegistersAndDoublesSlot(reg));
}
void MacroAssembler::StoreToSafepointRegisterSlot(Register reg) {
str(reg, SafepointRegisterSlot(reg));
}
void MacroAssembler::LoadFromSafepointRegisterSlot(Register reg) {
ldr(reg, SafepointRegisterSlot(reg));
}
int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
// The registers are pushed starting with the highest encoding,
// which means that lowest encodings are closest to the stack pointer.
......@@ -503,6 +513,14 @@ MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
}
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
// General purpose registers are pushed last on the stack.
int doubles_size = DwVfpRegister::kNumAllocatableRegisters * kDoubleSize;
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
return MemOperand(sp, doubles_size + register_offset);
}
void MacroAssembler::Ldrd(Register dst1, Register dst2,
const MemOperand& src, Condition cond) {
ASSERT(src.rm().is(no_reg));
......
......@@ -235,8 +235,11 @@ class MacroAssembler: public Assembler {
void PushSafepointRegistersAndDoubles();
void PopSafepointRegistersAndDoubles();
void StoreToSafepointRegisterSlot(Register reg);
void StoreToSafepointRegistersAndDoublesSlot(Register reg);
void LoadFromSafepointRegisterSlot(Register reg);
static int SafepointRegisterStackIndex(int reg_code);
static MemOperand SafepointRegisterSlot(Register reg);
static MemOperand SafepointRegistersAndDoublesSlot(Register reg);
// Load two consecutive registers with two consecutive memory locations.
void Ldrd(Register dst1,
......
......@@ -2445,6 +2445,11 @@ void Simulator::DecodeTypeVFP(Instruction* instr) {
int d = instr->VFPDRegValue(kSinglePrecision);
set_s_register_from_float(d, get_float_from_s_register(m));
}
} else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
// vabs
double dm_value = get_double_from_d_register(vm);
double dd_value = fabs(dm_value);
set_d_register_from_double(vd, dd_value);
} else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
} else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
......
......@@ -229,6 +229,8 @@ TEST(4) {
double d;
double e;
double f;
double g;
double h;
int i;
float x;
float y;
......@@ -286,6 +288,15 @@ TEST(4) {
__ vmov(s31, lr);
__ vcvt_f64_s32(d4, s31);
__ vstr(d4, r4, OFFSET_OF(T, f));
// Test vabs.
__ vldr(d1, r4, OFFSET_OF(T, g));
__ vabs(d0, d1);
__ vstr(d0, r4, OFFSET_OF(T, g));
__ vldr(d2, r4, OFFSET_OF(T, h));
__ vabs(d0, d2);
__ vstr(d0, r4, OFFSET_OF(T, h));
__ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
CodeDesc desc;
......@@ -305,6 +316,8 @@ TEST(4) {
t.d = 0.0;
t.e = 0.0;
t.f = 0.0;
t.g = -2718.2818;
t.h = 31415926.5;
t.i = 0;
t.x = 4.5;
t.y = 9.0;
......@@ -313,6 +326,8 @@ TEST(4) {
CHECK_EQ(4.5, t.y);
CHECK_EQ(9.0, t.x);
CHECK_EQ(2, t.i);
CHECK_EQ(2718.2818, t.g);
CHECK_EQ(31415926.5, t.h);
CHECK_EQ(42.0, t.f);
CHECK_EQ(1.0, t.e);
CHECK_EQ(1.000000059604644775390625, t.d);
......
......@@ -435,6 +435,11 @@ TEST(Vfp) {
COMPARE(vmov(s31, r10),
"ee0faa90 vmov s31, r10");
COMPARE(vabs(d0, d1),
"eeb00bc1 vabs d0, d1");
COMPARE(vabs(d3, d4, mi),
"4eb03bc4 vabsmi d3, d4");
COMPARE(vadd(d0, d1, d2),
"ee310b02 vadd.f64 d0, d1, d2");
COMPARE(vadd(d3, d4, d5, mi),
......
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