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
This commit is contained in:
parent
6d5451d685
commit
66d13be5f9
@ -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);
|
||||
}
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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<Instr*>(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);
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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<float>(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<uint32_t>(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<double>((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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user