diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 6df6411db6..7d368bf415 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -1809,6 +1809,7 @@ void Assembler::stc2(Coprocessor coproc, // Support for VFP. + void Assembler::vldr(const DwVfpRegister dst, const Register base, int offset, @@ -1838,7 +1839,9 @@ void Assembler::vldr(const SwVfpRegister dst, ASSERT(offset % 4 == 0); ASSERT((offset / 4) < 256); ASSERT(offset >= 0); - emit(cond | 0xD9*B20 | base.code()*B16 | dst.code()*B12 | + int sd, d; + dst.split_code(&sd, &d); + emit(cond | d*B22 | 0xD9*B20 | base.code()*B16 | sd*B12 | 0xA*B8 | ((offset / 4) & 255)); } @@ -1872,7 +1875,9 @@ void Assembler::vstr(const SwVfpRegister src, ASSERT(offset % 4 == 0); ASSERT((offset / 4) < 256); ASSERT(offset >= 0); - emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 | + int sd, d; + src.split_code(&sd, &d); + emit(cond | d*B22 | 0xD8*B20 | base.code()*B16 | sd*B12 | 0xA*B8 | ((offset / 4) & 255)); } @@ -1979,8 +1984,10 @@ void Assembler::vmov(const SwVfpRegister dst, // Sd = Sm // Instruction details available in ARM DDI 0406B, A8-642. ASSERT(CpuFeatures::IsEnabled(VFP3)); - emit(cond | 0xE*B24 | 0xB*B20 | - dst.code()*B12 | 0x5*B9 | B6 | src.code()); + int sd, d, sm, m; + dst.split_code(&sd, &d); + src.split_code(&sm, &m); + emit(cond | 0xE*B24 | d*B22 | 0xB*B20 | sd*B12 | 0xA*B8 | B6 | m*B5 | sm); } @@ -2034,8 +2041,9 @@ void Assembler::vmov(const SwVfpRegister dst, // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) ASSERT(CpuFeatures::IsEnabled(VFP3)); ASSERT(!src.is(pc)); - emit(cond | 0xE*B24 | (dst.code() >> 1)*B16 | - src.code()*B12 | 0xA*B8 | (0x1 & dst.code())*B7 | B4); + int sn, n; + dst.split_code(&sn, &n); + emit(cond | 0xE*B24 | sn*B16 | src.code()*B12 | 0xA*B8 | n*B7 | B4); } @@ -2048,8 +2056,9 @@ void Assembler::vmov(const Register dst, // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0) ASSERT(CpuFeatures::IsEnabled(VFP3)); ASSERT(!dst.is(pc)); - emit(cond | 0xE*B24 | B20 | (src.code() >> 1)*B16 | - dst.code()*B12 | 0xA*B8 | (0x1 & src.code())*B7 | B4); + int sn, n; + src.split_code(&sn, &n); + emit(cond | 0xE*B24 | B20 | sn*B16 | dst.code()*B12 | 0xA*B8 | n*B7 | B4); } @@ -2099,16 +2108,21 @@ static bool IsDoubleVFPType(VFPType type) { } -// Depending on split_last_bit split binary representation of reg_code into Vm:M -// or M:Vm form (where M is single bit). -static void SplitRegCode(bool split_last_bit, +// Split five bit reg_code based on size of reg_type. +// 32-bit register codes are Vm:M +// 64-bit register codes are M:Vm +// where Vm is four bits, and M is a single bit. +static void SplitRegCode(VFPType reg_type, int reg_code, int* vm, int* m) { - if (split_last_bit) { + ASSERT((reg_code >= 0) && (reg_code <= 31)); + if (IsIntegerVFPType(reg_type) || !IsDoubleVFPType(reg_type)) { + // 32 bit type. *m = reg_code & 0x1; *vm = reg_code >> 1; } else { + // 64 bit type. *m = (reg_code & 0x10) >> 4; *vm = reg_code & 0x0F; } @@ -2121,6 +2135,11 @@ static Instr EncodeVCVT(const VFPType dst_type, const VFPType src_type, const int src_code, const Condition cond) { + ASSERT(src_type != dst_type); + int D, Vd, M, Vm; + SplitRegCode(src_type, src_code, &Vm, &M); + SplitRegCode(dst_type, dst_code, &Vd, &D); + if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) { // Conversion between IEEE floating point and 32-bit integer. // Instruction details available in ARM DDI 0406B, A8.6.295. @@ -2128,22 +2147,17 @@ static Instr EncodeVCVT(const VFPType dst_type, // Vd(15-12) | 101(11-9) | sz(8) | op(7) | 1(6) | M(5) | 0(4) | Vm(3-0) ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type)); - int sz, opc2, D, Vd, M, Vm, op; + int sz, opc2, op; if (IsIntegerVFPType(dst_type)) { opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4; sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; op = 1; // round towards zero - SplitRegCode(!IsDoubleVFPType(src_type), src_code, &Vm, &M); - SplitRegCode(true, dst_code, &Vd, &D); } else { ASSERT(IsIntegerVFPType(src_type)); - opc2 = 0x0; sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0; op = IsSignedVFPType(src_type) ? 0x1 : 0x0; - SplitRegCode(true, src_code, &Vm, &M); - SplitRegCode(!IsDoubleVFPType(dst_type), dst_code, &Vd, &D); } return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 | @@ -2153,13 +2167,7 @@ static Instr EncodeVCVT(const VFPType dst_type, // Instruction details available in ARM DDI 0406B, A8.6.298. // cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) | // Vd(15-12) | 101(11-9) | sz(8) | 1(7) | 1(6) | M(5) | 0(4) | Vm(3-0) - int sz, D, Vd, M, Vm; - - ASSERT(IsDoubleVFPType(dst_type) != IsDoubleVFPType(src_type)); - sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; - SplitRegCode(IsDoubleVFPType(src_type), dst_code, &Vd, &D); - SplitRegCode(!IsDoubleVFPType(src_type), src_code, &Vm, &M); - + int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 | Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm); } diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index cc6ec05429..be9aa92f1a 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -120,6 +120,11 @@ struct SwVfpRegister { ASSERT(is_valid()); return 1 << code_; } + void split_code(int* vm, int* m) const { + ASSERT(is_valid()); + *m = code_ & 0x1; + *vm = code_ >> 1; + } int code_; }; @@ -152,6 +157,11 @@ struct DwVfpRegister { ASSERT(is_valid()); return 1 << code_; } + void split_code(int* vm, int* m) const { + ASSERT(is_valid()); + *m = (code_ & 0x10) >> 4; + *vm = code_ & 0x0F; + } int code_; }; diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h index 2ac9a41326..b2b5cb56b0 100644 --- a/src/arm/constants-arm.h +++ b/src/arm/constants-arm.h @@ -194,6 +194,13 @@ enum SoftwareInterruptCodes { }; +// Type of VFP register. Determines register encoding. +enum VFPRegPrecision { + kSinglePrecision = 0, + kDoublePrecision = 1 +}; + + typedef int32_t instr_t; @@ -269,6 +276,15 @@ class Instr { inline int VCField() const { return Bit(8); } inline int VAField() const { return Bits(23, 21); } inline int VBField() const { return Bits(6, 5); } + inline int VFPNRegCode(VFPRegPrecision pre) { + return VFPGlueRegCode(pre, 16, 7); + } + inline int VFPMRegCode(VFPRegPrecision pre) { + return VFPGlueRegCode(pre, 0, 5); + } + inline int VFPDRegCode(VFPRegPrecision pre) { + return VFPGlueRegCode(pre, 12, 22); + } // Fields used in Data processing instructions inline Opcode OpcodeField() const { @@ -343,6 +359,17 @@ class Instr { static Instr* At(byte* pc) { return reinterpret_cast(pc); } private: + // Join split register codes, depending on single or double precision. + // four_bit is the position of the least-significant bit of the four + // bit specifier. one_bit is the position of the additional single bit + // specifier. + inline int VFPGlueRegCode(VFPRegPrecision pre, int four_bit, int one_bit) { + if (pre == kSinglePrecision) { + return (Bits(four_bit + 3, four_bit) << 1) | Bit(one_bit); + } + return (Bit(one_bit) << 4) | Bits(four_bit + 3, four_bit); + } + // We need to prevent the creation of instances of class Instr. DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); }; diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index 0029ed168b..5122f437b9 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -463,7 +463,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) { ASSERT((width + lsb) <= 32); out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "#%d", + "%d", instr->Bits(width + lsb - 1, lsb)); return 8; } @@ -931,7 +931,7 @@ void Decoder::DecodeType3(Instr* instr) { if (instr->HasW()) { ASSERT(instr->Bits(5, 4) == 0x1); if (instr->Bit(22) == 0x1) { - Format(instr, "usat 'rd, 'imm05@16, 'rm'shift_sat"); + Format(instr, "usat 'rd, #'imm05@16, 'rm'shift_sat"); } else { UNREACHABLE(); // SSAT. } @@ -1269,17 +1269,19 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) { if (instr->CoprocessorField() == 0xA) { switch (instr->OpcodeField()) { case 0x8: + case 0xA: if (instr->HasL()) { - Format(instr, "vldr'cond 'Sd, ['rn - 4*'off8]"); + Format(instr, "vldr'cond 'Sd, ['rn - 4*'imm08@00]"); } else { - Format(instr, "vstr'cond 'Sd, ['rn - 4*'off8]"); + Format(instr, "vstr'cond 'Sd, ['rn - 4*'imm08@00]"); } break; case 0xC: + case 0xE: if (instr->HasL()) { - Format(instr, "vldr'cond 'Sd, ['rn + 4*'off8]"); + Format(instr, "vldr'cond 'Sd, ['rn + 4*'imm08@00]"); } else { - Format(instr, "vstr'cond 'Sd, ['rn + 4*'off8]"); + Format(instr, "vstr'cond 'Sd, ['rn + 4*'imm08@00]"); } break; default: @@ -1300,16 +1302,16 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) { break; case 0x8: if (instr->HasL()) { - Format(instr, "vldr'cond 'Dd, ['rn - 4*'off8]"); + Format(instr, "vldr'cond 'Dd, ['rn - 4*'imm08@00]"); } else { - Format(instr, "vstr'cond 'Dd, ['rn - 4*'off8]"); + Format(instr, "vstr'cond 'Dd, ['rn - 4*'imm08@00]"); } break; case 0xC: if (instr->HasL()) { - Format(instr, "vldr'cond 'Dd, ['rn + 4*'off8]"); + Format(instr, "vldr'cond 'Dd, ['rn + 4*'imm08@00]"); } else { - Format(instr, "vstr'cond 'Dd, ['rn + 4*'off8]"); + Format(instr, "vstr'cond 'Dd, ['rn + 4*'imm08@00]"); } break; default: diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index c7fc13f813..64262b2b81 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -2281,13 +2281,6 @@ void Simulator::DecodeUnconditional(Instr* instr) { } -// Depending on value of last_bit flag glue register code from vm and m values -// (where m is expected to be a single bit). -static int GlueRegCode(bool last_bit, int vm, int m) { - return last_bit ? ((vm << 1) | m) : ((m << 4) | vm); -} - - // void Simulator::DecodeTypeVFP(Instr* instr) // The Following ARMv7 VFPv instructions are currently supported. // vmov :Sn = Rt @@ -2305,9 +2298,10 @@ void Simulator::DecodeTypeVFP(Instr* instr) { ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); ASSERT(instr->Bits(11, 9) == 0x5); - int vm = instr->VmField(); - int vd = instr->VdField(); - int vn = instr->VnField(); + // Obtain double precision register codes. + int vm = instr->VFPMRegCode(kDoublePrecision); + int vd = instr->VFPDRegCode(kDoublePrecision); + int vn = instr->VFPNRegCode(kDoublePrecision); if (instr->Bit(4) == 0) { if (instr->Opc1Field() == 0x7) { @@ -2315,9 +2309,13 @@ void Simulator::DecodeTypeVFP(Instr* instr) { if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) { // vmov register to register. if (instr->SzField() == 0x1) { - set_d_register_from_double(vd, get_double_from_d_register(vm)); + int m = instr->VFPMRegCode(kDoublePrecision); + int d = instr->VFPDRegCode(kDoublePrecision); + set_d_register_from_double(d, get_double_from_d_register(m)); } else { - set_s_register_from_float(vd, get_float_from_s_register(vm)); + int m = instr->VFPMRegCode(kSinglePrecision); + int d = instr->VFPDRegCode(kSinglePrecision); + set_s_register_from_float(d, get_float_from_s_register(m)); } } else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) { DecodeVCVTBetweenDoubleAndSingle(instr); @@ -2410,7 +2408,7 @@ void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { (instr->VAField() == 0x0)); int t = instr->RtField(); - int n = GlueRegCode(true, instr->VnField(), instr->NField()); + int n = instr->VFPNRegCode(kSinglePrecision); bool to_arm_register = (instr->VLField() == 0x1); if (to_arm_register) { @@ -2427,22 +2425,25 @@ void Simulator::DecodeVCMP(Instr* instr) { ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && (instr->Opc3Field() & 0x1)); - // Comparison. - bool dp_operation = (instr->SzField() == 1); + + VFPRegPrecision precision = kSinglePrecision; + if (instr->SzField() == 1) { + precision = kDoublePrecision; + } if (instr->Bit(7) != 0) { // Raising exceptions for quiet NaNs are not supported. UNIMPLEMENTED(); // Not used by V8. } - int d = GlueRegCode(!dp_operation, instr->VdField(), instr->DField()); + int d = instr->VFPDRegCode(precision); int m = 0; if (instr->Opc2Field() == 0x4) { - m = GlueRegCode(!dp_operation, instr->VmField(), instr->MField()); + m = instr->VFPMRegCode(precision); } - if (dp_operation) { + if (precision == kDoublePrecision) { double dd_value = get_double_from_d_register(d); double dm_value = 0.0; if (instr->Opc2Field() == 0x4) { @@ -2460,11 +2461,17 @@ void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)); - bool double_to_single = (instr->SzField() == 1); - int dst = GlueRegCode(double_to_single, instr->VdField(), instr->DField()); - int src = GlueRegCode(!double_to_single, instr->VmField(), instr->MField()); + VFPRegPrecision dst_precision = kDoublePrecision; + VFPRegPrecision src_precision = kSinglePrecision; + if (instr->SzField() == 1) { + dst_precision = kSinglePrecision; + src_precision = kDoublePrecision; + } - if (double_to_single) { + int dst = instr->VFPDRegCode(dst_precision); + int src = instr->VFPMRegCode(src_precision); + + if (dst_precision == kSinglePrecision) { double val = get_double_from_d_register(src); set_s_register_from_float(dst, static_cast(val)); } else { @@ -2480,13 +2487,13 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1))); // Conversion between floating-point and integer. - int vd = instr->VdField(); - int d = instr->DField(); - int vm = instr->VmField(); - int m = instr->MField(); - bool to_integer = (instr->Bit(18) == 1); - bool dp_operation = (instr->SzField() == 1); + + VFPRegPrecision src_precision = kSinglePrecision; + if (instr->SzField() == 1) { + src_precision = kDoublePrecision; + } + if (to_integer) { bool unsigned_integer = (instr->Bit(16) == 0); if (instr->Bit(7) != 1) { @@ -2494,10 +2501,10 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { UNIMPLEMENTED(); // Not used by V8. } - int dst = GlueRegCode(true, vd, d); - int src = GlueRegCode(!dp_operation, vm, m); + int dst = instr->VFPDRegCode(kSinglePrecision); + int src = instr->VFPMRegCode(src_precision); - if (dp_operation) { + if (src_precision == kDoublePrecision) { double val = get_double_from_d_register(src); int sint = unsigned_integer ? static_cast(val) : @@ -2515,12 +2522,12 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { } else { bool unsigned_integer = (instr->Bit(7) == 0); - int dst = GlueRegCode(!dp_operation, vd, d); - int src = GlueRegCode(true, vm, m); + int dst = instr->VFPDRegCode(src_precision); + int src = instr->VFPMRegCode(kSinglePrecision); int val = get_sinteger_from_s_register(src); - if (dp_operation) { + if (src_precision == kDoublePrecision) { if (unsigned_integer) { set_d_register_from_double(dst, static_cast((uint32_t)val)); @@ -2551,9 +2558,11 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) { if (instr->CoprocessorField() == 0xA) { switch (instr->OpcodeField()) { case 0x8: - case 0xC: { // Load and store float to memory. + case 0xA: + case 0xC: + case 0xE: { // Load and store single precision float to memory. int rn = instr->RnField(); - int vd = instr->VdField(); + int vd = instr->VFPDRegCode(kSinglePrecision); int offset = instr->Immed8Field(); if (!instr->HasU()) { offset = -offset; diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc index 5952b636ff..fee6624132 100644 --- a/test/cctest/test-assembler-arm.cc +++ b/test/cctest/test-assembler-arm.cc @@ -226,13 +226,17 @@ TEST(4) { double a; double b; double c; - float d; - float e; + double d; + double e; + double f; + int i; + float x; + float y; } T; T t; // Create a function that accepts &t, and loads, manipulates, and stores - // the doubles t.a, t.b, and t.c, and floats t.d, t.e. + // the doubles and floats. Assembler assm(NULL, 0); Label L, C; @@ -254,15 +258,34 @@ TEST(4) { __ vmov(d4, r2, r3); __ vstr(d4, r4, OFFSET_OF(T, b)); - // Load t.d and t.e, switch values, and store back to the struct. - __ vldr(s0, r4, OFFSET_OF(T, d)); - __ vldr(s1, r4, OFFSET_OF(T, e)); - __ vmov(s2, s0); - __ vmov(s0, s1); - __ vmov(s1, s2); - __ vstr(s0, r4, OFFSET_OF(T, d)); - __ vstr(s1, r4, OFFSET_OF(T, e)); + // Load t.x and t.y, switch values, and store back to the struct. + __ vldr(s0, r4, OFFSET_OF(T, x)); + __ vldr(s31, r4, OFFSET_OF(T, y)); + __ vmov(s16, s0); + __ vmov(s0, s31); + __ vmov(s31, s16); + __ vstr(s0, r4, OFFSET_OF(T, x)); + __ vstr(s31, r4, OFFSET_OF(T, y)); + // Move a literal into a register that can be encoded in the instruction. + __ vmov(d4, 1.0); + __ vstr(d4, r4, OFFSET_OF(T, e)); + + // Move a literal into a register that requires 64 bits to encode. + // 0x3ff0000010000000 = 1.000000059604644775390625 + __ vmov(d4, 1.000000059604644775390625); + __ vstr(d4, r4, OFFSET_OF(T, d)); + + // Convert from floating point to integer. + __ vmov(d4, 2.0); + __ vcvt_s32_f64(s31, d4); + __ vstr(s31, r4, OFFSET_OF(T, i)); + + // Convert from integer to floating point. + __ mov(lr, Operand(42)); + __ vmov(s31, lr); + __ vcvt_f64_s32(d4, s31); + __ vstr(d4, r4, OFFSET_OF(T, f)); __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); CodeDesc desc; @@ -278,12 +301,20 @@ TEST(4) { t.a = 1.5; t.b = 2.75; t.c = 17.17; - t.d = 4.5; - t.e = 9.0; + t.d = 0.0; + t.e = 0.0; + t.f = 0.0; + t.i = 0; + t.x = 4.5; + t.y = 9.0; Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); USE(dummy); - CHECK_EQ(4.5, t.e); - CHECK_EQ(9.0, t.d); + CHECK_EQ(4.5, t.y); + CHECK_EQ(9.0, t.x); + CHECK_EQ(2, t.i); + CHECK_EQ(42.0, t.f); + CHECK_EQ(1.0, t.e); + CHECK_EQ(1.000000059604644775390625, t.d); CHECK_EQ(4.25, t.c); CHECK_EQ(4.25, t.b); CHECK_EQ(1.5, t.a); diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc index 0ba4f9ae47..61f5ffc727 100644 --- a/test/cctest/test-disasm-arm.cc +++ b/test/cctest/test-disasm-arm.cc @@ -422,6 +422,19 @@ TEST(Vfp) { COMPARE(vmov(d3, d3, eq), "0eb03b43 vmov.f64eq d3, d3"); + COMPARE(vmov(s0, s31), + "eeb00a6f vmov.f32 s0, s31"); + COMPARE(vmov(s31, s0), + "eef0fa40 vmov.f32 s31, s0"); + COMPARE(vmov(r0, s0), + "ee100a10 vmov r0, s0"); + COMPARE(vmov(r10, s31), + "ee1faa90 vmov r10, s31"); + COMPARE(vmov(s0, r0), + "ee000a10 vmov s0, r0"); + COMPARE(vmov(s31, r10), + "ee0faa90 vmov s31, r10"); + COMPARE(vadd(d0, d1, d2), "ee310b02 vadd.f64 d0, d1, d2"); COMPARE(vadd(d3, d4, d5, mi), @@ -451,6 +464,41 @@ TEST(Vfp) { "eeb70b00 vmov.f64 d0, #1"); COMPARE(vmov(d2, -13.0), "eeba2b0a vmov.f64 d2, #-13"); + + COMPARE(vldr(s0, r0, 0), + "ed900a00 vldr s0, [r0 + 4*0]"); + COMPARE(vldr(s1, r1, 4), + "edd10a01 vldr s1, [r1 + 4*1]"); + COMPARE(vldr(s15, r4, 16), + "edd47a04 vldr s15, [r4 + 4*4]"); + COMPARE(vldr(s16, r5, 20), + "ed958a05 vldr s16, [r5 + 4*5]"); + COMPARE(vldr(s31, r10, 1020), + "eddafaff vldr s31, [r10 + 4*255]"); + + COMPARE(vstr(s0, r0, 0), + "ed800a00 vstr s0, [r0 + 4*0]"); + COMPARE(vstr(s1, r1, 4), + "edc10a01 vstr s1, [r1 + 4*1]"); + COMPARE(vstr(s15, r8, 8), + "edc87a02 vstr s15, [r8 + 4*2]"); + COMPARE(vstr(s16, r9, 12), + "ed898a03 vstr s16, [r9 + 4*3]"); + COMPARE(vstr(s31, r10, 1020), + "edcafaff vstr s31, [r10 + 4*255]"); + + COMPARE(vldr(d0, r0, 0), + "ed900b00 vldr d0, [r0 + 4*0]"); + COMPARE(vldr(d1, r1, 4), + "ed911b01 vldr d1, [r1 + 4*1]"); + COMPARE(vldr(d15, r10, 1020), + "ed9afbff vldr d15, [r10 + 4*255]"); + COMPARE(vstr(d0, r0, 0), + "ed800b00 vstr d0, [r0 + 4*0]"); + COMPARE(vstr(d1, r1, 4), + "ed811b01 vstr d1, [r1 + 4*1]"); + COMPARE(vstr(d15, r10, 1020), + "ed8afbff vstr d15, [r10 + 4*255]"); } VERIFY_RUN();