Commit 66d13be5 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Fix incorrect encoding of single and double precision registers for some VFP...

Fix incorrect encoding of single and double precision registers for some VFP instructions. Also fix incorrect disassembling of vldr/vstr.  This is a commit of http://codereview.chromium.org/3107027 for Rodolph Perfetta.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5352 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6d5451d6
...@@ -1809,6 +1809,7 @@ void Assembler::stc2(Coprocessor coproc, ...@@ -1809,6 +1809,7 @@ void Assembler::stc2(Coprocessor coproc,
// Support for VFP. // Support for VFP.
void Assembler::vldr(const DwVfpRegister dst, void Assembler::vldr(const DwVfpRegister dst,
const Register base, const Register base,
int offset, int offset,
...@@ -1838,7 +1839,9 @@ void Assembler::vldr(const SwVfpRegister dst, ...@@ -1838,7 +1839,9 @@ void Assembler::vldr(const SwVfpRegister dst,
ASSERT(offset % 4 == 0); ASSERT(offset % 4 == 0);
ASSERT((offset / 4) < 256); ASSERT((offset / 4) < 256);
ASSERT(offset >= 0); 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)); 0xA*B8 | ((offset / 4) & 255));
} }
...@@ -1872,7 +1875,9 @@ void Assembler::vstr(const SwVfpRegister src, ...@@ -1872,7 +1875,9 @@ void Assembler::vstr(const SwVfpRegister src,
ASSERT(offset % 4 == 0); ASSERT(offset % 4 == 0);
ASSERT((offset / 4) < 256); ASSERT((offset / 4) < 256);
ASSERT(offset >= 0); 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)); 0xA*B8 | ((offset / 4) & 255));
} }
...@@ -1979,8 +1984,10 @@ void Assembler::vmov(const SwVfpRegister dst, ...@@ -1979,8 +1984,10 @@ void Assembler::vmov(const SwVfpRegister dst,
// Sd = Sm // Sd = Sm
// Instruction details available in ARM DDI 0406B, A8-642. // Instruction details available in ARM DDI 0406B, A8-642.
ASSERT(CpuFeatures::IsEnabled(VFP3)); ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xB*B20 | int sd, d, sm, m;
dst.code()*B12 | 0x5*B9 | B6 | src.code()); 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, ...@@ -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) // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3)); ASSERT(CpuFeatures::IsEnabled(VFP3));
ASSERT(!src.is(pc)); ASSERT(!src.is(pc));
emit(cond | 0xE*B24 | (dst.code() >> 1)*B16 | int sn, n;
src.code()*B12 | 0xA*B8 | (0x1 & dst.code())*B7 | B4); 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, ...@@ -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) // Rt(15-12) | 1010(11-8) | N(7)=0 | 00(6-5) | 1(4) | 0000(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3)); ASSERT(CpuFeatures::IsEnabled(VFP3));
ASSERT(!dst.is(pc)); ASSERT(!dst.is(pc));
emit(cond | 0xE*B24 | B20 | (src.code() >> 1)*B16 | int sn, n;
dst.code()*B12 | 0xA*B8 | (0x1 & src.code())*B7 | B4); 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) { ...@@ -2099,16 +2108,21 @@ static bool IsDoubleVFPType(VFPType type) {
} }
// Depending on split_last_bit split binary representation of reg_code into Vm:M // Split five bit reg_code based on size of reg_type.
// or M:Vm form (where M is single bit). // 32-bit register codes are Vm:M
static void SplitRegCode(bool split_last_bit, // 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 reg_code,
int* vm, int* vm,
int* m) { 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; *m = reg_code & 0x1;
*vm = reg_code >> 1; *vm = reg_code >> 1;
} else { } else {
// 64 bit type.
*m = (reg_code & 0x10) >> 4; *m = (reg_code & 0x10) >> 4;
*vm = reg_code & 0x0F; *vm = reg_code & 0x0F;
} }
...@@ -2121,6 +2135,11 @@ static Instr EncodeVCVT(const VFPType dst_type, ...@@ -2121,6 +2135,11 @@ static Instr EncodeVCVT(const VFPType dst_type,
const VFPType src_type, const VFPType src_type,
const int src_code, const int src_code,
const Condition cond) { 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)) { if (IsIntegerVFPType(dst_type) || IsIntegerVFPType(src_type)) {
// Conversion between IEEE floating point and 32-bit integer. // Conversion between IEEE floating point and 32-bit integer.
// Instruction details available in ARM DDI 0406B, A8.6.295. // Instruction details available in ARM DDI 0406B, A8.6.295.
...@@ -2128,22 +2147,17 @@ static Instr EncodeVCVT(const VFPType dst_type, ...@@ -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) // 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)); ASSERT(!IsIntegerVFPType(dst_type) || !IsIntegerVFPType(src_type));
int sz, opc2, D, Vd, M, Vm, op; int sz, opc2, op;
if (IsIntegerVFPType(dst_type)) { if (IsIntegerVFPType(dst_type)) {
opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4; opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0; sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
op = 1; // round towards zero op = 1; // round towards zero
SplitRegCode(!IsDoubleVFPType(src_type), src_code, &Vm, &M);
SplitRegCode(true, dst_code, &Vd, &D);
} else { } else {
ASSERT(IsIntegerVFPType(src_type)); ASSERT(IsIntegerVFPType(src_type));
opc2 = 0x0; opc2 = 0x0;
sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0; sz = IsDoubleVFPType(dst_type) ? 0x1 : 0x0;
op = IsSignedVFPType(src_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 | return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | B19 | opc2*B16 |
...@@ -2153,13 +2167,7 @@ static Instr EncodeVCVT(const VFPType dst_type, ...@@ -2153,13 +2167,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
// Instruction details available in ARM DDI 0406B, A8.6.298. // Instruction details available in ARM DDI 0406B, A8.6.298.
// cond(31-28) | 11101(27-23)| D(22) | 11(21-20) | 0111(19-16) | // 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) // 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; int sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
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);
return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 | return (cond | 0xE*B24 | B23 | D*B22 | 0x3*B20 | 0x7*B16 |
Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm); Vd*B12 | 0x5*B9 | sz*B8 | B7 | B6 | M*B5 | Vm);
} }
......
...@@ -120,6 +120,11 @@ struct SwVfpRegister { ...@@ -120,6 +120,11 @@ struct SwVfpRegister {
ASSERT(is_valid()); ASSERT(is_valid());
return 1 << code_; return 1 << code_;
} }
void split_code(int* vm, int* m) const {
ASSERT(is_valid());
*m = code_ & 0x1;
*vm = code_ >> 1;
}
int code_; int code_;
}; };
...@@ -152,6 +157,11 @@ struct DwVfpRegister { ...@@ -152,6 +157,11 @@ struct DwVfpRegister {
ASSERT(is_valid()); ASSERT(is_valid());
return 1 << code_; return 1 << code_;
} }
void split_code(int* vm, int* m) const {
ASSERT(is_valid());
*m = (code_ & 0x10) >> 4;
*vm = code_ & 0x0F;
}
int code_; int code_;
}; };
......
...@@ -194,6 +194,13 @@ enum SoftwareInterruptCodes { ...@@ -194,6 +194,13 @@ enum SoftwareInterruptCodes {
}; };
// Type of VFP register. Determines register encoding.
enum VFPRegPrecision {
kSinglePrecision = 0,
kDoublePrecision = 1
};
typedef int32_t instr_t; typedef int32_t instr_t;
...@@ -269,6 +276,15 @@ class Instr { ...@@ -269,6 +276,15 @@ class Instr {
inline int VCField() const { return Bit(8); } inline int VCField() const { return Bit(8); }
inline int VAField() const { return Bits(23, 21); } inline int VAField() const { return Bits(23, 21); }
inline int VBField() const { return Bits(6, 5); } 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 // Fields used in Data processing instructions
inline Opcode OpcodeField() const { inline Opcode OpcodeField() const {
...@@ -343,6 +359,17 @@ class Instr { ...@@ -343,6 +359,17 @@ class Instr {
static Instr* At(byte* pc) { return reinterpret_cast<Instr*>(pc); } static Instr* At(byte* pc) { return reinterpret_cast<Instr*>(pc); }
private: 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. // We need to prevent the creation of instances of class Instr.
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
}; };
......
...@@ -463,7 +463,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) { ...@@ -463,7 +463,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
ASSERT((width + lsb) <= 32); ASSERT((width + lsb) <= 32);
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"#%d", "%d",
instr->Bits(width + lsb - 1, lsb)); instr->Bits(width + lsb - 1, lsb));
return 8; return 8;
} }
...@@ -931,7 +931,7 @@ void Decoder::DecodeType3(Instr* instr) { ...@@ -931,7 +931,7 @@ void Decoder::DecodeType3(Instr* instr) {
if (instr->HasW()) { if (instr->HasW()) {
ASSERT(instr->Bits(5, 4) == 0x1); ASSERT(instr->Bits(5, 4) == 0x1);
if (instr->Bit(22) == 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 { } else {
UNREACHABLE(); // SSAT. UNREACHABLE(); // SSAT.
} }
...@@ -1269,17 +1269,19 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) { ...@@ -1269,17 +1269,19 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
if (instr->CoprocessorField() == 0xA) { if (instr->CoprocessorField() == 0xA) {
switch (instr->OpcodeField()) { switch (instr->OpcodeField()) {
case 0x8: case 0x8:
case 0xA:
if (instr->HasL()) { if (instr->HasL()) {
Format(instr, "vldr'cond 'Sd, ['rn - 4*'off8]"); Format(instr, "vldr'cond 'Sd, ['rn - 4*'imm08@00]");
} else { } else {
Format(instr, "vstr'cond 'Sd, ['rn - 4*'off8]"); Format(instr, "vstr'cond 'Sd, ['rn - 4*'imm08@00]");
} }
break; break;
case 0xC: case 0xC:
case 0xE:
if (instr->HasL()) { if (instr->HasL()) {
Format(instr, "vldr'cond 'Sd, ['rn + 4*'off8]"); Format(instr, "vldr'cond 'Sd, ['rn + 4*'imm08@00]");
} else { } else {
Format(instr, "vstr'cond 'Sd, ['rn + 4*'off8]"); Format(instr, "vstr'cond 'Sd, ['rn + 4*'imm08@00]");
} }
break; break;
default: default:
...@@ -1300,16 +1302,16 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) { ...@@ -1300,16 +1302,16 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
break; break;
case 0x8: case 0x8:
if (instr->HasL()) { if (instr->HasL()) {
Format(instr, "vldr'cond 'Dd, ['rn - 4*'off8]"); Format(instr, "vldr'cond 'Dd, ['rn - 4*'imm08@00]");
} else { } else {
Format(instr, "vstr'cond 'Dd, ['rn - 4*'off8]"); Format(instr, "vstr'cond 'Dd, ['rn - 4*'imm08@00]");
} }
break; break;
case 0xC: case 0xC:
if (instr->HasL()) { if (instr->HasL()) {
Format(instr, "vldr'cond 'Dd, ['rn + 4*'off8]"); Format(instr, "vldr'cond 'Dd, ['rn + 4*'imm08@00]");
} else { } else {
Format(instr, "vstr'cond 'Dd, ['rn + 4*'off8]"); Format(instr, "vstr'cond 'Dd, ['rn + 4*'imm08@00]");
} }
break; break;
default: default:
......
...@@ -2281,13 +2281,6 @@ void Simulator::DecodeUnconditional(Instr* instr) { ...@@ -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) // void Simulator::DecodeTypeVFP(Instr* instr)
// The Following ARMv7 VFPv instructions are currently supported. // The Following ARMv7 VFPv instructions are currently supported.
// vmov :Sn = Rt // vmov :Sn = Rt
...@@ -2305,9 +2298,10 @@ void Simulator::DecodeTypeVFP(Instr* instr) { ...@@ -2305,9 +2298,10 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) ); ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
ASSERT(instr->Bits(11, 9) == 0x5); ASSERT(instr->Bits(11, 9) == 0x5);
int vm = instr->VmField(); // Obtain double precision register codes.
int vd = instr->VdField(); int vm = instr->VFPMRegCode(kDoublePrecision);
int vn = instr->VnField(); int vd = instr->VFPDRegCode(kDoublePrecision);
int vn = instr->VFPNRegCode(kDoublePrecision);
if (instr->Bit(4) == 0) { if (instr->Bit(4) == 0) {
if (instr->Opc1Field() == 0x7) { if (instr->Opc1Field() == 0x7) {
...@@ -2315,9 +2309,13 @@ void Simulator::DecodeTypeVFP(Instr* instr) { ...@@ -2315,9 +2309,13 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) { if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) {
// vmov register to register. // vmov register to register.
if (instr->SzField() == 0x1) { 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 { } 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)) { } else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr); DecodeVCVTBetweenDoubleAndSingle(instr);
...@@ -2410,7 +2408,7 @@ void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) { ...@@ -2410,7 +2408,7 @@ void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) {
(instr->VAField() == 0x0)); (instr->VAField() == 0x0));
int t = instr->RtField(); int t = instr->RtField();
int n = GlueRegCode(true, instr->VnField(), instr->NField()); int n = instr->VFPNRegCode(kSinglePrecision);
bool to_arm_register = (instr->VLField() == 0x1); bool to_arm_register = (instr->VLField() == 0x1);
if (to_arm_register) { if (to_arm_register) {
...@@ -2427,22 +2425,25 @@ void Simulator::DecodeVCMP(Instr* instr) { ...@@ -2427,22 +2425,25 @@ void Simulator::DecodeVCMP(Instr* instr) {
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) && ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
(instr->Opc3Field() & 0x1)); (instr->Opc3Field() & 0x1));
// Comparison. // Comparison.
bool dp_operation = (instr->SzField() == 1);
VFPRegPrecision precision = kSinglePrecision;
if (instr->SzField() == 1) {
precision = kDoublePrecision;
}
if (instr->Bit(7) != 0) { if (instr->Bit(7) != 0) {
// Raising exceptions for quiet NaNs are not supported. // Raising exceptions for quiet NaNs are not supported.
UNIMPLEMENTED(); // Not used by V8. UNIMPLEMENTED(); // Not used by V8.
} }
int d = GlueRegCode(!dp_operation, instr->VdField(), instr->DField()); int d = instr->VFPDRegCode(precision);
int m = 0; int m = 0;
if (instr->Opc2Field() == 0x4) { 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 dd_value = get_double_from_d_register(d);
double dm_value = 0.0; double dm_value = 0.0;
if (instr->Opc2Field() == 0x4) { if (instr->Opc2Field() == 0x4) {
...@@ -2460,11 +2461,17 @@ void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) { ...@@ -2460,11 +2461,17 @@ void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) {
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7)); ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)); ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3));
bool double_to_single = (instr->SzField() == 1); VFPRegPrecision dst_precision = kDoublePrecision;
int dst = GlueRegCode(double_to_single, instr->VdField(), instr->DField()); VFPRegPrecision src_precision = kSinglePrecision;
int src = GlueRegCode(!double_to_single, instr->VmField(), instr->MField()); 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); double val = get_double_from_d_register(src);
set_s_register_from_float(dst, static_cast<float>(val)); set_s_register_from_float(dst, static_cast<float>(val));
} else { } else {
...@@ -2480,13 +2487,13 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { ...@@ -2480,13 +2487,13 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
(((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1))); (((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1)));
// Conversion between floating-point and integer. // 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 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) { if (to_integer) {
bool unsigned_integer = (instr->Bit(16) == 0); bool unsigned_integer = (instr->Bit(16) == 0);
if (instr->Bit(7) != 1) { if (instr->Bit(7) != 1) {
...@@ -2494,10 +2501,10 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { ...@@ -2494,10 +2501,10 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
UNIMPLEMENTED(); // Not used by V8. UNIMPLEMENTED(); // Not used by V8.
} }
int dst = GlueRegCode(true, vd, d); int dst = instr->VFPDRegCode(kSinglePrecision);
int src = GlueRegCode(!dp_operation, vm, m); int src = instr->VFPMRegCode(src_precision);
if (dp_operation) { if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src); double val = get_double_from_d_register(src);
int sint = unsigned_integer ? static_cast<uint32_t>(val) : int sint = unsigned_integer ? static_cast<uint32_t>(val) :
...@@ -2515,12 +2522,12 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) { ...@@ -2515,12 +2522,12 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
} else { } else {
bool unsigned_integer = (instr->Bit(7) == 0); bool unsigned_integer = (instr->Bit(7) == 0);
int dst = GlueRegCode(!dp_operation, vd, d); int dst = instr->VFPDRegCode(src_precision);
int src = GlueRegCode(true, vm, m); int src = instr->VFPMRegCode(kSinglePrecision);
int val = get_sinteger_from_s_register(src); int val = get_sinteger_from_s_register(src);
if (dp_operation) { if (src_precision == kDoublePrecision) {
if (unsigned_integer) { if (unsigned_integer) {
set_d_register_from_double(dst, set_d_register_from_double(dst,
static_cast<double>((uint32_t)val)); static_cast<double>((uint32_t)val));
...@@ -2551,9 +2558,11 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) { ...@@ -2551,9 +2558,11 @@ void Simulator::DecodeType6CoprocessorIns(Instr* instr) {
if (instr->CoprocessorField() == 0xA) { if (instr->CoprocessorField() == 0xA) {
switch (instr->OpcodeField()) { switch (instr->OpcodeField()) {
case 0x8: 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 rn = instr->RnField();
int vd = instr->VdField(); int vd = instr->VFPDRegCode(kSinglePrecision);
int offset = instr->Immed8Field(); int offset = instr->Immed8Field();
if (!instr->HasU()) { if (!instr->HasU()) {
offset = -offset; offset = -offset;
......
...@@ -226,13 +226,17 @@ TEST(4) { ...@@ -226,13 +226,17 @@ TEST(4) {
double a; double a;
double b; double b;
double c; double c;
float d; double d;
float e; double e;
double f;
int i;
float x;
float y;
} T; } T;
T t; T t;
// Create a function that accepts &t, and loads, manipulates, and stores // 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); Assembler assm(NULL, 0);
Label L, C; Label L, C;
...@@ -254,15 +258,34 @@ TEST(4) { ...@@ -254,15 +258,34 @@ TEST(4) {
__ vmov(d4, r2, r3); __ vmov(d4, r2, r3);
__ vstr(d4, r4, OFFSET_OF(T, b)); __ vstr(d4, r4, OFFSET_OF(T, b));
// Load t.d and t.e, switch values, and store back to the struct. // Load t.x and t.y, switch values, and store back to the struct.
__ vldr(s0, r4, OFFSET_OF(T, d)); __ vldr(s0, r4, OFFSET_OF(T, x));
__ vldr(s1, r4, OFFSET_OF(T, e)); __ vldr(s31, r4, OFFSET_OF(T, y));
__ vmov(s2, s0); __ vmov(s16, s0);
__ vmov(s0, s1); __ vmov(s0, s31);
__ vmov(s1, s2); __ vmov(s31, s16);
__ vstr(s0, r4, OFFSET_OF(T, d)); __ vstr(s0, r4, OFFSET_OF(T, x));
__ vstr(s1, r4, OFFSET_OF(T, e)); __ 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()); __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
CodeDesc desc; CodeDesc desc;
...@@ -278,12 +301,20 @@ TEST(4) { ...@@ -278,12 +301,20 @@ TEST(4) {
t.a = 1.5; t.a = 1.5;
t.b = 2.75; t.b = 2.75;
t.c = 17.17; t.c = 17.17;
t.d = 4.5; t.d = 0.0;
t.e = 9.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); Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
USE(dummy); USE(dummy);
CHECK_EQ(4.5, t.e); CHECK_EQ(4.5, t.y);
CHECK_EQ(9.0, t.d); 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.c);
CHECK_EQ(4.25, t.b); CHECK_EQ(4.25, t.b);
CHECK_EQ(1.5, t.a); CHECK_EQ(1.5, t.a);
......
...@@ -422,6 +422,19 @@ TEST(Vfp) { ...@@ -422,6 +422,19 @@ TEST(Vfp) {
COMPARE(vmov(d3, d3, eq), COMPARE(vmov(d3, d3, eq),
"0eb03b43 vmov.f64eq d3, d3"); "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), COMPARE(vadd(d0, d1, d2),
"ee310b02 vadd.f64 d0, d1, d2"); "ee310b02 vadd.f64 d0, d1, d2");
COMPARE(vadd(d3, d4, d5, mi), COMPARE(vadd(d3, d4, d5, mi),
...@@ -451,6 +464,41 @@ TEST(Vfp) { ...@@ -451,6 +464,41 @@ TEST(Vfp) {
"eeb70b00 vmov.f64 d0, #1"); "eeb70b00 vmov.f64 d0, #1");
COMPARE(vmov(d2, -13.0), COMPARE(vmov(d2, -13.0),
"eeba2b0a vmov.f64 d2, #-13"); "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(); VERIFY_RUN();
......
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