From: m.m.capewell@googlemail.com Date: Thu, 25 Jul 2013 15:04:38 +0000 (+0000) Subject: ARM: Make double registers low/high safe X-Git-Tag: upstream/4.7.83~13200 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cc9398cd4260c75c5c84a94733f2238dd3a962d8;p=platform%2Fupstream%2Fv8.git ARM: Make double registers low/high safe This patch prevents taking the low/high part of a double-precision VFP register that has no corresponding single-precision VFP registers. BUG=none TEST=Added to test-disasm-arm.cc, test-assembler-arm.cc Review URL: https://codereview.chromium.org/19560003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15885 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index d95946e..ba0dc4b 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -2373,15 +2373,16 @@ void Assembler::vmov(const DwVfpRegister dst, if (scratch.is(no_reg)) { if (dst.code() < 16) { + const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code()); // Move the low part of the double into the lower of the corresponsing S // registers of D register dst. mov(ip, Operand(lo)); - vmov(dst.low(), ip); + vmov(loc.low(), ip); // Move the high part of the double into the higher of the // corresponsing S registers of D register dst. mov(ip, Operand(hi)); - vmov(dst.high(), ip); + vmov(loc.high(), ip); } else { // D16-D31 does not have S registers, so move the low and high parts // directly to the D register using vmov.32. @@ -2446,6 +2447,22 @@ void Assembler::vmov(const DwVfpRegister dst, } +void Assembler::vmov(const Register dst, + const VmovIndex index, + const DwVfpRegister src, + const Condition cond) { + // Dd[index] = Rt + // Instruction details available in ARM DDI 0406C.b, A8.8.342. + // cond(31-28) | 1110(27-24) | U=0(23) | opc1=0index(22-21) | 1(20) | + // Vn(19-16) | Rt(15-12) | 1011(11-8) | N(7) | opc2=00(6-5) | 1(4) | 0000(3-0) + ASSERT(index.index == 0 || index.index == 1); + int vn, n; + src.split_code(&vn, &n); + emit(cond | 0xE*B24 | index.index*B21 | B20 | vn*B16 | dst.code()*B12 | + 0xB*B8 | n*B7 | B4); +} + + void Assembler::vmov(const DwVfpRegister dst, const Register src1, const Register src2, diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 62dd94c..496eb3e 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -267,22 +267,6 @@ struct DwVfpRegister { return 0 <= code_ && code_ < kMaxNumRegisters; } bool is(DwVfpRegister reg) const { return code_ == reg.code_; } - SwVfpRegister low() const { - ASSERT(code_ < 16); - SwVfpRegister reg; - reg.code_ = code_ * 2; - - ASSERT(reg.is_valid()); - return reg; - } - SwVfpRegister high() const { - ASSERT(code_ < 16); - SwVfpRegister reg; - reg.code_ = (code_ * 2) + 1; - - ASSERT(reg.is_valid()); - return reg; - } int code() const { ASSERT(is_valid()); return code_; @@ -304,6 +288,47 @@ struct DwVfpRegister { typedef DwVfpRegister DoubleRegister; +// Double word VFP register d0-15. +struct LowDwVfpRegister { + public: + static const int kMaxNumLowRegisters = 16; + operator DwVfpRegister() const { + DwVfpRegister r = { code_ }; + return r; + } + static LowDwVfpRegister from_code(int code) { + LowDwVfpRegister r = { code }; + return r; + } + + bool is_valid() const { + return 0 <= code_ && code_ < kMaxNumLowRegisters; + } + bool is(DwVfpRegister reg) const { return code_ == reg.code_; } + bool is(LowDwVfpRegister reg) const { return code_ == reg.code_; } + int code() const { + ASSERT(is_valid()); + return code_; + } + SwVfpRegister low() const { + SwVfpRegister reg; + reg.code_ = code_ * 2; + + ASSERT(reg.is_valid()); + return reg; + } + SwVfpRegister high() const { + SwVfpRegister reg; + reg.code_ = (code_ * 2) + 1; + + ASSERT(reg.is_valid()); + return reg; + } + + int code_; +}; + + // Quad word NEON register. struct QwNeonRegister { static const int kMaxNumRegisters = 16; @@ -370,22 +395,22 @@ const SwVfpRegister s30 = { 30 }; const SwVfpRegister s31 = { 31 }; const DwVfpRegister no_dreg = { -1 }; -const DwVfpRegister d0 = { 0 }; -const DwVfpRegister d1 = { 1 }; -const DwVfpRegister d2 = { 2 }; -const DwVfpRegister d3 = { 3 }; -const DwVfpRegister d4 = { 4 }; -const DwVfpRegister d5 = { 5 }; -const DwVfpRegister d6 = { 6 }; -const DwVfpRegister d7 = { 7 }; -const DwVfpRegister d8 = { 8 }; -const DwVfpRegister d9 = { 9 }; -const DwVfpRegister d10 = { 10 }; -const DwVfpRegister d11 = { 11 }; -const DwVfpRegister d12 = { 12 }; -const DwVfpRegister d13 = { 13 }; -const DwVfpRegister d14 = { 14 }; -const DwVfpRegister d15 = { 15 }; +const LowDwVfpRegister d0 = { 0 }; +const LowDwVfpRegister d1 = { 1 }; +const LowDwVfpRegister d2 = { 2 }; +const LowDwVfpRegister d3 = { 3 }; +const LowDwVfpRegister d4 = { 4 }; +const LowDwVfpRegister d5 = { 5 }; +const LowDwVfpRegister d6 = { 6 }; +const LowDwVfpRegister d7 = { 7 }; +const LowDwVfpRegister d8 = { 8 }; +const LowDwVfpRegister d9 = { 9 }; +const LowDwVfpRegister d10 = { 10 }; +const LowDwVfpRegister d11 = { 11 }; +const LowDwVfpRegister d12 = { 12 }; +const LowDwVfpRegister d13 = { 13 }; +const LowDwVfpRegister d14 = { 14 }; +const LowDwVfpRegister d15 = { 15 }; const DwVfpRegister d16 = { 16 }; const DwVfpRegister d17 = { 17 }; const DwVfpRegister d18 = { 18 }; @@ -420,6 +445,7 @@ const QwNeonRegister q13 = { 13 }; const QwNeonRegister q14 = { 14 }; const QwNeonRegister q15 = { 15 }; + // Aliases for double registers. Defined using #define instead of // "static const DwVfpRegister&" because Clang complains otherwise when a // compilation unit that includes this header doesn't use the variables. @@ -1109,6 +1135,10 @@ class Assembler : public AssemblerBase { const VmovIndex index, const Register src, const Condition cond = al); + void vmov(const Register dst, + const VmovIndex index, + const DwVfpRegister src, + const Condition cond = al); void vmov(const DwVfpRegister dst, const Register src1, const Register src2, diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index f45c75b..ba98b96 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -1897,7 +1897,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Register right = r0; Register scratch1 = r7; Register scratch2 = r9; - DwVfpRegister double_scratch = d0; + LowDwVfpRegister double_scratch = d0; Register heap_number_result = no_reg; Register heap_number_map = r6; @@ -1972,7 +1972,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { Label not_zero; ASSERT(kSmiTag == 0); __ b(ne, ¬_zero); - __ vmov(scratch2, d5.high()); + __ VmovHigh(scratch2, d5); __ tst(scratch2, Operand(HeapNumber::kSignMask)); __ b(ne, &transition); __ bind(¬_zero); @@ -3817,7 +3817,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX))); // Copy the JS object part. - __ CopyFields(r0, r4, d0, s0, JSObject::kHeaderSize / kPointerSize); + __ CopyFields(r0, r4, d0, JSObject::kHeaderSize / kPointerSize); // Get the length (smi tagged) and set that as an in-object property too. STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); @@ -6804,7 +6804,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. __ bind(&double_elements); __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); - __ StoreNumberToDoubleElements(r0, r3, r5, r6, &slow_elements); + __ StoreNumberToDoubleElements(r0, r3, r5, r6, d0, &slow_elements); __ Ret(); } diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index fd986fd..ecdf638 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -1345,6 +1345,14 @@ void Decoder::DecodeTypeVFP(Instruction* instr) { } else { Format(instr, "vmov'cond.32 'Dd[1], 'rt"); } + } else if ((instr->VLValue() == 0x1) && + (instr->VCValue() == 0x1) && + (instr->Bit(23) == 0x0)) { + if (instr->Bit(21) == 0x0) { + Format(instr, "vmov'cond.32 'rt, 'Dd[0]"); + } else { + Format(instr, "vmov'cond.32 'rt, 'Dd[1]"); + } } else if ((instr->VCValue() == 0x0) && (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) { diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 6a5845d..ea7b73f 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1623,7 +1623,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { // r0: Newly allocated regexp. // r5: Materialized regexp. // r2: temp. - __ CopyFields(r0, r5, d0, s0, size / kPointerSize); + __ CopyFields(r0, r5, d0, size / kPointerSize); context()->Plug(r0); } diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index ee28d28..f43846c 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -1361,7 +1361,7 @@ static void KeyedStoreGenerateGenericHelper( __ b(ne, slow); } __ bind(&fast_double_without_map_check); - __ StoreNumberToDoubleElements(value, key, elements, r3, + __ StoreNumberToDoubleElements(value, key, elements, r3, d0, &transition_double_elements); if (increment_length == kIncrementLength) { // Add 1 to receiver->length. diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 65abeca..0000146 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2057,7 +2057,7 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { Representation input_rep = value->representation(); LOperand* reg = UseRegister(value); if (input_rep.IsDouble()) { - return DefineAsRegister(new(zone()) LClampDToUint8(reg, FixedTemp(d11))); + return DefineAsRegister(new(zone()) LClampDToUint8(reg)); } else if (input_rep.IsInteger32()) { return DefineAsRegister(new(zone()) LClampIToUint8(reg)); } else { diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 616b2da..6faa781 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -2420,15 +2420,13 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { }; -class LClampDToUint8: public LTemplateInstruction<1, 1, 1> { +class LClampDToUint8: public LTemplateInstruction<1, 1, 0> { public: - LClampDToUint8(LOperand* unclamped, LOperand* temp) { + explicit LClampDToUint8(LOperand* unclamped) { inputs_[0] = unclamped; - temps_[0] = temp; } LOperand* unclamped() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8") }; diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 8f28651..41636a8 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1190,7 +1190,7 @@ void LCodeGen::DoModI(LModI* instr) { DwVfpRegister dividend = ToDoubleRegister(instr->temp()); DwVfpRegister divisor = ToDoubleRegister(instr->temp2()); ASSERT(!divisor.is(dividend)); - DwVfpRegister quotient = double_scratch0(); + LowDwVfpRegister quotient = double_scratch0(); ASSERT(!quotient.is(dividend)); ASSERT(!quotient.is(divisor)); @@ -1206,11 +1206,10 @@ void LCodeGen::DoModI(LModI* instr) { // Load the arguments in VFP registers. The divisor value is preloaded // before. Be careful that 'right_reg' is only live on entry. // TODO(svenpanne) The last comments seems to be wrong nowadays. - __ vmov(dividend.low(), left_reg); - __ vmov(divisor.low(), right_reg); - - __ vcvt_f64_s32(dividend, dividend.low()); - __ vcvt_f64_s32(divisor, divisor.low()); + __ vmov(double_scratch0().low(), left_reg); + __ vcvt_f64_s32(dividend, double_scratch0().low()); + __ vmov(double_scratch0().low(), right_reg); + __ vcvt_f64_s32(divisor, double_scratch0().low()); // We do not care about the sign of the divisor. Note that we still handle // the kMinInt % -1 case correctly, though. @@ -1221,10 +1220,9 @@ void LCodeGen::DoModI(LModI* instr) { __ vcvt_f64_s32(quotient, quotient.low()); // Compute the remainder in result. - DwVfpRegister double_scratch = dividend; - __ vmul(double_scratch, divisor, quotient); - __ vcvt_s32_f64(double_scratch.low(), double_scratch); - __ vmov(scratch, double_scratch.low()); + __ vmul(double_scratch0(), divisor, quotient); + __ vcvt_s32_f64(double_scratch0().low(), double_scratch0()); + __ vmov(scratch, double_scratch0().low()); __ sub(result_reg, left_reg, scratch, SetCC); // If we care about -0, test if the dividend is <0 and the result is 0. @@ -1424,20 +1422,20 @@ void LCodeGen::DoDivI(LDivI* instr) { } else { const DoubleRegister vleft = ToDoubleRegister(instr->temp()); const DoubleRegister vright = double_scratch0(); - __ vmov(vleft.low(), left); - __ vmov(vright.low(), right); - __ vcvt_f64_s32(vleft, vleft.low()); - __ vcvt_f64_s32(vright, vright.low()); + __ vmov(double_scratch0().low(), left); + __ vcvt_f64_s32(vleft, double_scratch0().low()); + __ vmov(double_scratch0().low(), right); + __ vcvt_f64_s32(vright, double_scratch0().low()); __ vdiv(vleft, vleft, vright); // vleft now contains the result. - __ vcvt_s32_f64(vright.low(), vleft); - __ vmov(result, vright.low()); + __ vcvt_s32_f64(double_scratch0().low(), vleft); + __ vmov(result, double_scratch0().low()); if (!instr->hydrogen()->CheckFlag( HInstruction::kAllUsesTruncatingToInt32)) { // Deopt if exact conversion to integer was not possible. // Use vright as scratch register. - __ vcvt_f64_s32(vright, vright.low()); - __ VFPCompareAndSetFlags(vleft, vright); + __ vcvt_f64_s32(double_scratch0(), double_scratch0().low()); + __ VFPCompareAndSetFlags(vleft, double_scratch0()); DeoptimizeIf(ne, instr->environment()); } } @@ -3210,8 +3208,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { : Operand(key, LSL, shift_size); __ add(scratch0(), external_pointer, operand); if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - __ vldr(kScratchDoubleReg.low(), scratch0(), additional_offset); - __ vcvt_f64_f32(result, kScratchDoubleReg.low()); + __ vldr(double_scratch0().low(), scratch0(), additional_offset); + __ vcvt_f64_f32(result, double_scratch0().low()); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS __ vldr(result, scratch0(), additional_offset); } @@ -3779,7 +3777,6 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) { Register input_high = scratch0(); Label done, exact; - __ vmov(input_high, input.high()); __ TryInt32Floor(result, input, input_high, double_scratch0(), &done, &exact); DeoptimizeIf(al, instr->environment()); @@ -3812,7 +3809,7 @@ void LCodeGen::DoMathRound(LMathRound* instr) { // If the input is +0.5, the result is 1. __ b(hi, &convert); // Out of [-0.5, +0.5]. if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - __ vmov(input_high, input.high()); + __ VmovHigh(input_high, input); __ cmp(input_high, Operand::Zero()); DeoptimizeIf(mi, instr->environment()); // [-0.5, -0]. } @@ -3825,7 +3822,6 @@ void LCodeGen::DoMathRound(LMathRound* instr) { __ bind(&convert); __ vadd(input_plus_dot_five, input, dot_five); - __ vmov(input_high, input_plus_dot_five.high()); // Reuse dot_five (double_scratch0) as we no longer need this value. __ TryInt32Floor(result, input_plus_dot_five, input_high, double_scratch0(), &done, &done); @@ -4761,8 +4757,7 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, Label slow; Register src = ToRegister(value); Register dst = ToRegister(instr->result()); - DwVfpRegister dbl_scratch = double_scratch0(); - SwVfpRegister flt_scratch = dbl_scratch.low(); + LowDwVfpRegister dbl_scratch = double_scratch0(); // Preserve the value of all registers. PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); @@ -4776,11 +4771,11 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, __ SmiUntag(src, dst); __ eor(src, src, Operand(0x80000000)); } - __ vmov(flt_scratch, src); - __ vcvt_f64_s32(dbl_scratch, flt_scratch); + __ vmov(dbl_scratch.low(), src); + __ vcvt_f64_s32(dbl_scratch, dbl_scratch.low()); } else { - __ vmov(flt_scratch, src); - __ vcvt_f64_u32(dbl_scratch, flt_scratch); + __ vmov(dbl_scratch.low(), src); + __ vcvt_f64_u32(dbl_scratch, dbl_scratch.low()); } if (FLAG_inline_new) { @@ -4841,7 +4836,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { DwVfpRegister input_reg = ToDoubleRegister(instr->value()); __ VFPCompareAndSetFlags(input_reg, input_reg); __ b(vc, &no_special_nan_handling); - __ vmov(scratch, input_reg.high()); + __ VmovHigh(scratch, input_reg); __ cmp(scratch, Operand(kHoleNanUpper32)); // If not the hole NaN, force the NaN to be canonical. __ VFPCanonicalizeNaN(input_reg, ne); @@ -4941,22 +4936,20 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, DeoptimizeIf(ne, env); __ bind(&convert); - __ LoadRoot(ip, Heap::kNanValueRootIndex); - __ sub(ip, ip, Operand(kHeapObjectTag)); - __ vldr(result_reg, ip, HeapNumber::kValueOffset); + __ LoadRoot(scratch, Heap::kNanValueRootIndex); + __ vldr(result_reg, scratch, HeapNumber::kValueOffset - kHeapObjectTag); __ jmp(&done); __ bind(&heap_number); } // Heap number to double register conversion. - __ sub(ip, input_reg, Operand(kHeapObjectTag)); - __ vldr(result_reg, ip, HeapNumber::kValueOffset); + __ vldr(result_reg, input_reg, HeapNumber::kValueOffset - kHeapObjectTag); if (deoptimize_on_minus_zero) { - __ vmov(ip, result_reg.low()); - __ cmp(ip, Operand::Zero()); + __ VmovLow(scratch, result_reg); + __ cmp(scratch, Operand::Zero()); __ b(ne, &done); - __ vmov(ip, result_reg.high()); - __ cmp(ip, Operand(HeapNumber::kSignMask)); + __ VmovHigh(scratch, result_reg); + __ cmp(scratch, Operand(HeapNumber::kSignMask)); DeoptimizeIf(eq, env); } __ jmp(&done); @@ -4978,7 +4971,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { Register input_reg = ToRegister(instr->value()); Register scratch1 = scratch0(); Register scratch2 = ToRegister(instr->temp()); - DwVfpRegister double_scratch = double_scratch0(); + LowDwVfpRegister double_scratch = double_scratch0(); DwVfpRegister double_scratch2 = ToDoubleRegister(instr->temp3()); ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); @@ -5026,14 +5019,14 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { DeoptimizeIf(ne, instr->environment()); __ sub(ip, input_reg, Operand(kHeapObjectTag)); - __ vldr(double_scratch, ip, HeapNumber::kValueOffset); - __ TryDoubleToInt32Exact(input_reg, double_scratch, double_scratch2); + __ vldr(double_scratch2, ip, HeapNumber::kValueOffset); + __ TryDoubleToInt32Exact(input_reg, double_scratch2, double_scratch); DeoptimizeIf(ne, instr->environment()); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ cmp(input_reg, Operand::Zero()); __ b(ne, &done); - __ vmov(scratch1, double_scratch.high()); + __ VmovHigh(scratch1, double_scratch2); __ tst(scratch1, Operand(HeapNumber::kSignMask)); DeoptimizeIf(ne, instr->environment()); } @@ -5106,7 +5099,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register scratch1 = scratch0(); Register scratch2 = ToRegister(instr->temp()); DwVfpRegister double_input = ToDoubleRegister(instr->value()); - DwVfpRegister double_scratch = double_scratch0(); + LowDwVfpRegister double_scratch = double_scratch0(); if (instr->truncating()) { Register scratch3 = ToRegister(instr->temp2()); @@ -5120,7 +5113,7 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Label done; __ cmp(result_reg, Operand::Zero()); __ b(ne, &done); - __ vmov(scratch1, double_input.high()); + __ VmovHigh(scratch1, double_input); __ tst(scratch1, Operand(HeapNumber::kSignMask)); DeoptimizeIf(ne, instr->environment()); __ bind(&done); @@ -5134,7 +5127,7 @@ void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { Register scratch1 = scratch0(); Register scratch2 = ToRegister(instr->temp()); DwVfpRegister double_input = ToDoubleRegister(instr->value()); - DwVfpRegister double_scratch = double_scratch0(); + LowDwVfpRegister double_scratch = double_scratch0(); if (instr->truncating()) { Register scratch3 = ToRegister(instr->temp2()); @@ -5148,7 +5141,7 @@ void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { Label done; __ cmp(result_reg, Operand::Zero()); __ b(ne, &done); - __ vmov(scratch1, double_input.high()); + __ VmovHigh(scratch1, double_input); __ tst(scratch1, Operand(HeapNumber::kSignMask)); DeoptimizeIf(ne, instr->environment()); __ bind(&done); @@ -5269,8 +5262,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { DwVfpRegister value_reg = ToDoubleRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DwVfpRegister temp_reg = ToDoubleRegister(instr->temp()); - __ ClampDoubleToUint8(result_reg, value_reg, temp_reg); + __ ClampDoubleToUint8(result_reg, value_reg, double_scratch0()); } @@ -5305,9 +5297,8 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { // Heap number __ bind(&heap_number); - __ vldr(double_scratch0(), FieldMemOperand(input_reg, - HeapNumber::kValueOffset)); - __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg); + __ vldr(temp_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); + __ ClampDoubleToUint8(result_reg, temp_reg, double_scratch0()); __ jmp(&done); // smi @@ -5480,8 +5471,7 @@ void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { __ bind(&allocated); // Copy the content into the newly allocated memory. - __ CopyFields(r0, r1, double_scratch0(), double_scratch0().low(), - size / kPointerSize); + __ CopyFields(r0, r1, double_scratch0(), size / kPointerSize); } diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index ae4a09f..21f7921 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h @@ -200,7 +200,7 @@ class LCodeGen BASE_EMBEDDED { HGraph* graph() const { return chunk()->graph(); } Register scratch0() { return r9; } - DwVfpRegister double_scratch0() { return kScratchDoubleReg; } + LowDwVfpRegister double_scratch0() { return kScratchDoubleReg; } int GetNextEmittedBlock() const; LInstruction* GetNextInstruction(); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index ba80cda..cd12461 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -792,6 +792,46 @@ void MacroAssembler::Vmov(const DwVfpRegister dst, } +void MacroAssembler::VmovHigh(Register dst, DwVfpRegister src) { + if (src.code() < 16) { + const LowDwVfpRegister loc = LowDwVfpRegister::from_code(src.code()); + vmov(dst, loc.high()); + } else { + vmov(dst, VmovIndexHi, src); + } +} + + +void MacroAssembler::VmovHigh(DwVfpRegister dst, Register src) { + if (dst.code() < 16) { + const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code()); + vmov(loc.high(), src); + } else { + vmov(dst, VmovIndexHi, src); + } +} + + +void MacroAssembler::VmovLow(Register dst, DwVfpRegister src) { + if (src.code() < 16) { + const LowDwVfpRegister loc = LowDwVfpRegister::from_code(src.code()); + vmov(dst, loc.low()); + } else { + vmov(dst, VmovIndexLo, src); + } +} + + +void MacroAssembler::VmovLow(DwVfpRegister dst, Register src) { + if (dst.code() < 16) { + const LowDwVfpRegister loc = LowDwVfpRegister::from_code(dst.code()); + vmov(loc.low(), src); + } else { + vmov(dst, VmovIndexLo, src); + } +} + + void MacroAssembler::ConvertNumberToInt32(Register object, Register dst, Register heap_number_map, @@ -799,7 +839,7 @@ void MacroAssembler::ConvertNumberToInt32(Register object, Register scratch2, Register scratch3, DwVfpRegister double_scratch1, - DwVfpRegister double_scratch2, + LowDwVfpRegister double_scratch2, Label* not_number) { Label done; UntagAndJumpIfSmi(dst, object, &done); @@ -813,7 +853,7 @@ void MacroAssembler::ConvertNumberToInt32(Register object, void MacroAssembler::LoadNumber(Register object, - DwVfpRegister dst, + LowDwVfpRegister dst, Register heap_number_map, Register scratch, Label* not_number) { @@ -838,7 +878,7 @@ void MacroAssembler::LoadNumberAsInt32Double(Register object, DwVfpRegister double_dst, Register heap_number_map, Register scratch, - DwVfpRegister double_scratch, + LowDwVfpRegister double_scratch, Label* not_int32) { ASSERT(!scratch.is(object)); ASSERT(!heap_number_map.is(object) && !heap_number_map.is(scratch)); @@ -870,7 +910,7 @@ void MacroAssembler::LoadNumberAsInt32(Register object, Register heap_number_map, Register scratch, DwVfpRegister double_scratch0, - DwVfpRegister double_scratch1, + LowDwVfpRegister double_scratch1, Label* not_int32) { ASSERT(!dst.is(object)); ASSERT(!scratch.is(object)); @@ -2066,12 +2106,14 @@ void MacroAssembler::CheckFastSmiElements(Register map, } -void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, - Register key_reg, - Register elements_reg, - Register scratch1, - Label* fail, - int elements_offset) { +void MacroAssembler::StoreNumberToDoubleElements( + Register value_reg, + Register key_reg, + Register elements_reg, + Register scratch1, + LowDwVfpRegister double_scratch, + Label* fail, + int elements_offset) { Label smi_value, store; // Handle smi values specially. @@ -2084,23 +2126,24 @@ void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, fail, DONT_DO_SMI_CHECK); - vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); + vldr(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); // Force a canonical NaN. if (emit_debug_code()) { vmrs(ip); tst(ip, Operand(kVFPDefaultNaNModeControlBit)); Assert(ne, "Default NaN mode not set"); } - VFPCanonicalizeNaN(d0); + VFPCanonicalizeNaN(double_scratch); b(&store); bind(&smi_value); - SmiToDouble(d0, value_reg); + SmiToDouble(double_scratch, value_reg); bind(&store); add(scratch1, elements_reg, Operand::DoubleOffsetFromSmiKey(key_reg)); - vstr(d0, FieldMemOperand(scratch1, - FixedDoubleArray::kHeaderSize - elements_offset)); + vstr(double_scratch, + FieldMemOperand(scratch1, + FixedDoubleArray::kHeaderSize - elements_offset)); } @@ -2406,8 +2449,7 @@ void MacroAssembler::IndexFromHash(Register hash, Register index) { } -void MacroAssembler::SmiToDouble(DwVfpRegister value, Register smi) { - ASSERT(value.code() < 16); +void MacroAssembler::SmiToDouble(LowDwVfpRegister value, Register smi) { if (CpuFeatures::IsSupported(VFP3)) { vmov(value.low(), smi); vcvt_f64_s32(value, 1); @@ -2420,7 +2462,7 @@ void MacroAssembler::SmiToDouble(DwVfpRegister value, Register smi) { void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input, - DwVfpRegister double_scratch) { + LowDwVfpRegister double_scratch) { ASSERT(!double_input.is(double_scratch)); vcvt_s32_f64(double_scratch.low(), double_input); vcvt_f64_s32(double_scratch, double_scratch.low()); @@ -2430,7 +2472,7 @@ void MacroAssembler::TestDoubleIsInt32(DwVfpRegister double_input, void MacroAssembler::TryDoubleToInt32Exact(Register result, DwVfpRegister double_input, - DwVfpRegister double_scratch) { + LowDwVfpRegister double_scratch) { ASSERT(!double_input.is(double_scratch)); vcvt_s32_f64(double_scratch.low(), double_input); vmov(result, double_scratch.low()); @@ -2442,13 +2484,15 @@ void MacroAssembler::TryDoubleToInt32Exact(Register result, void MacroAssembler::TryInt32Floor(Register result, DwVfpRegister double_input, Register input_high, - DwVfpRegister double_scratch, + LowDwVfpRegister double_scratch, Label* done, Label* exact) { ASSERT(!result.is(input_high)); ASSERT(!double_input.is(double_scratch)); Label negative, exception; + VmovHigh(input_high, double_input); + // Test for NaN and infinities. Sbfx(result, input_high, HeapNumber::kExponentShift, HeapNumber::kExponentBits); @@ -2489,7 +2533,7 @@ void MacroAssembler::ECMAToInt32(Register result, Register scratch, Register scratch_high, Register scratch_low, - DwVfpRegister double_scratch) { + LowDwVfpRegister double_scratch) { ASSERT(!scratch_high.is(result)); ASSERT(!scratch_low.is(result)); ASSERT(!scratch_low.is(scratch_high)); @@ -3143,8 +3187,7 @@ void MacroAssembler::AllocateHeapNumberWithValue(Register result, // Copies a fixed number of fields of heap objects from src to dst. void MacroAssembler::CopyFields(Register dst, Register src, - DwVfpRegister double_scratch, - SwVfpRegister single_scratch, + LowDwVfpRegister double_scratch, int field_count) { int double_count = field_count / (DwVfpRegister::kSizeInBytes / kPointerSize); for (int i = 0; i < double_count; i++) { @@ -3157,9 +3200,9 @@ void MacroAssembler::CopyFields(Register dst, int remain = field_count % (DwVfpRegister::kSizeInBytes / kPointerSize); if (remain != 0) { - vldr(single_scratch, + vldr(double_scratch.low(), FieldMemOperand(src, (field_count - 1) * kPointerSize)); - vstr(single_scratch, + vstr(double_scratch.low(), FieldMemOperand(dst, (field_count - 1) * kPointerSize)); } } @@ -3660,13 +3703,12 @@ void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) { void MacroAssembler::ClampDoubleToUint8(Register result_reg, DwVfpRegister input_reg, - DwVfpRegister temp_double_reg) { + LowDwVfpRegister double_scratch) { Label above_zero; Label done; Label in_bounds; - Vmov(temp_double_reg, 0.0); - VFPCompareAndSetFlags(input_reg, temp_double_reg); + VFPCompareAndSetFlags(input_reg, 0.0); b(gt, &above_zero); // Double value is less than zero, NaN or Inf, return 0. @@ -3675,8 +3717,8 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg, // Double value is >= 255, return 255. bind(&above_zero); - Vmov(temp_double_reg, 255.0, result_reg); - VFPCompareAndSetFlags(input_reg, temp_double_reg); + Vmov(double_scratch, 255.0, result_reg); + VFPCompareAndSetFlags(input_reg, double_scratch); b(le, &in_bounds); mov(result_reg, Operand(255)); b(al, &done); @@ -3688,8 +3730,8 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg, // Set rounding mode to round to the nearest integer by clearing bits[23:22]. bic(result_reg, ip, Operand(kVFPRoundingModeMask)); vmsr(result_reg); - vcvt_s32_f64(input_reg.low(), input_reg, kFPSCRRounding); - vmov(result_reg, input_reg.low()); + vcvt_s32_f64(double_scratch.low(), input_reg, kFPSCRRounding); + vmov(result_reg, double_scratch.low()); // Restore FPSCR. vmsr(ip); bind(&done); diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 747dd3b..38308e5 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -484,6 +484,11 @@ class MacroAssembler: public Assembler { const double imm, const Register scratch = no_reg); + void VmovHigh(Register dst, DwVfpRegister src); + void VmovHigh(DwVfpRegister dst, Register src); + void VmovLow(Register dst, DwVfpRegister src); + void VmovLow(DwVfpRegister dst, Register src); + // Converts the smi or heap number in object to an int32 using the rules // for ToInt32 as described in ECMAScript 9.5.: the value is truncated // and brought into the range -2^31 .. +2^31 - 1. @@ -494,14 +499,14 @@ class MacroAssembler: public Assembler { Register scratch2, Register scratch3, DwVfpRegister double_scratch1, - DwVfpRegister double_scratch2, + LowDwVfpRegister double_scratch2, Label* not_int32); // Loads the number from object into dst register. // If |object| is neither smi nor heap number, |not_number| is jumped to // with |object| still intact. void LoadNumber(Register object, - DwVfpRegister dst, + LowDwVfpRegister dst, Register heap_number_map, Register scratch, Label* not_number); @@ -515,7 +520,7 @@ class MacroAssembler: public Assembler { DwVfpRegister double_dst, Register heap_number_map, Register scratch, - DwVfpRegister double_scratch, + LowDwVfpRegister double_scratch, Label* not_int32); // Loads the number from object into dst as a 32-bit integer. @@ -528,7 +533,7 @@ class MacroAssembler: public Assembler { Register heap_number_map, Register scratch, DwVfpRegister double_scratch0, - DwVfpRegister double_scratch1, + LowDwVfpRegister double_scratch1, Label* not_int32); @@ -796,8 +801,7 @@ class MacroAssembler: public Assembler { // Copies a fixed number of fields of heap objects from src to dst. void CopyFields(Register dst, Register src, - DwVfpRegister double_scratch, - SwVfpRegister single_scratch, + LowDwVfpRegister double_scratch, int field_count); // Copies a number of bytes from src to dst. All registers are clobbered. On @@ -874,6 +878,7 @@ class MacroAssembler: public Assembler { Register key_reg, Register elements_reg, Register scratch1, + LowDwVfpRegister double_scratch, Label* fail, int elements_offset = 0); @@ -957,26 +962,27 @@ class MacroAssembler: public Assembler { // Load the value of a smi object into a double register. // The register value must be between d0 and d15. - void SmiToDouble(DwVfpRegister value, Register smi); + void SmiToDouble(LowDwVfpRegister value, Register smi); // Check if a double can be exactly represented as a signed 32-bit integer. // Z flag set to one if true. void TestDoubleIsInt32(DwVfpRegister double_input, - DwVfpRegister double_scratch); + LowDwVfpRegister double_scratch); // Try to convert a double to a signed 32-bit integer. // Z flag set to one and result assigned if the conversion is exact. void TryDoubleToInt32Exact(Register result, DwVfpRegister double_input, - DwVfpRegister double_scratch); + LowDwVfpRegister double_scratch); // Floor a double and writes the value to the result register. // Go to exact if the conversion is exact (to be able to test -0), // fall through calling code if an overflow occurred, else go to done. + // In return, input_high is loaded with high bits of input. void TryInt32Floor(Register result, DwVfpRegister double_input, Register input_high, - DwVfpRegister double_scratch, + LowDwVfpRegister double_scratch, Label* done, Label* exact); @@ -989,7 +995,7 @@ class MacroAssembler: public Assembler { Register scratch, Register scratch_high, Register scratch_low, - DwVfpRegister double_scratch); + LowDwVfpRegister double_scratch); // Check whether d16-d31 are available on the CPU. The result is given by the // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise. @@ -1311,7 +1317,7 @@ class MacroAssembler: public Assembler { void ClampDoubleToUint8(Register result_reg, DwVfpRegister input_reg, - DwVfpRegister temp_double_reg); + LowDwVfpRegister double_scratch); void LoadInstanceDescriptors(Register map, Register descriptors); diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index c47f2ab..c9e3616 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -3111,6 +3111,15 @@ void Simulator::DecodeTypeVFP(Instruction* instr) { OS::MemCopy(&dd_value, data, 8); set_d_register_from_double(vd, dd_value); } else if ((instr->VLValue() == 0x1) && + (instr->VCValue() == 0x1) && + (instr->Bit(23) == 0x0)) { + // vmov (scalar to ARM core register) + int vn = instr->Bits(19, 16) | (instr->Bit(7) << 4); + double dn_value = get_double_from_d_register(vn); + int32_t data[2]; + OS::MemCopy(data, &dn_value, 8); + set_register(instr->RtValue(), data[instr->Bit(21)]); + } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x0) && (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) { diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index ccf83f7..f7fa9ef 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -1813,7 +1813,7 @@ Handle CallStubCompiler::CompileArrayPushCall( __ b(gt, &call_builtin); __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); - __ StoreNumberToDoubleElements(r4, r0, elements, r5, + __ StoreNumberToDoubleElements(r4, r0, elements, r5, d0, &call_builtin, argc * kDoubleSize); // Save new length. @@ -3194,7 +3194,7 @@ static void GenerateSmiKeyCheck(MacroAssembler* masm, Register key, Register scratch0, DwVfpRegister double_scratch0, - DwVfpRegister double_scratch1, + LowDwVfpRegister double_scratch1, Label* fail) { Label key_ok; // Check for smi or a smi inside a heap number. We convert the heap @@ -3603,7 +3603,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ bind(&finish_store); __ StoreNumberToDoubleElements(value_reg, key_reg, elements_reg, - scratch1, &transition_elements_kind); + scratch1, d0, &transition_elements_kind); __ Ret(); // Handle store cache miss, replacing the ic with the generic stub. @@ -3651,7 +3651,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( __ mov(scratch1, elements_reg); __ StoreNumberToDoubleElements(value_reg, key_reg, scratch1, - scratch2, &transition_elements_kind); + scratch2, d0, &transition_elements_kind); __ mov(scratch1, Operand(kHoleNanLower32)); __ mov(scratch2, Operand(kHoleNanUpper32)); diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc index c79e740..cb677b3 100644 --- a/test/cctest/test-assembler-arm.cc +++ b/test/cctest/test-assembler-arm.cc @@ -1049,6 +1049,8 @@ TEST(13) { double i; double j; double k; + uint32_t low; + uint32_t high; } T; T t; @@ -1113,6 +1115,11 @@ TEST(13) { __ vmov(d22, VmovIndexHi, r2); __ add(r4, r0, Operand(OFFSET_OF(T, i))); __ vstm(ia_w, r4, d20, d22); + // Move d22 into low and high. + __ vmov(r4, VmovIndexLo, d22); + __ str(r4, MemOperand(r0, OFFSET_OF(T, low))); + __ vmov(r4, VmovIndexHi, d22); + __ str(r4, MemOperand(r0, OFFSET_OF(T, high))); __ ldm(ia_w, sp, r4.bit() | pc.bit()); @@ -1144,6 +1151,8 @@ TEST(13) { CHECK_EQ(14.7610017472335499, t.i); CHECK_EQ(16.0, t.j); CHECK_EQ(73.8818412254460241, t.k); + CHECK_EQ(372106121, t.low); + CHECK_EQ(1079146608, t.high); } } diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc index 9d6623e..2a53d43 100644 --- a/test/cctest/test-disasm-arm.cc +++ b/test/cctest/test-disasm-arm.cc @@ -500,6 +500,11 @@ TEST(Vfp) { COMPARE(vmov(d0, VmovIndexHi, r0), "ee200b10 vmov.32 d0[1], r0"); + COMPARE(vmov(r2, VmovIndexLo, d15), + "ee1f2b10 vmov.32 r2, d15[0]"); + COMPARE(vmov(r3, VmovIndexHi, d14), + "ee3e3b10 vmov.32 r3, d14[1]"); + COMPARE(vldr(s0, r0, 0), "ed900a00 vldr s0, [r0 + 4*0]"); COMPARE(vldr(s1, r1, 4),