Commit 8ebe8e47 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

ARM: The Simulator will now handle different VFP rounding modes. RZ and RM are...

ARM: The Simulator will now handle different VFP rounding modes. RZ and RM are implemented.  This is a commit of 
http://codereview.chromium.org/4295003/show for Alexander Rames of ARM.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5790 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c86e548e
......@@ -9,6 +9,7 @@ ARM Ltd.
Hewlett-Packard Development Company, LP
Alexander Botero-Lowry <alexbl@FreeBSD.org>
Alexandre Rames <alexandre.rames@arm.com>
Alexandre Vassalotti <avassalotti@gmail.com>
Andreas Anyuru <andreas.anyuru@gmail.com>
Burcu Dogan <burcujdogan@gmail.com>
......
......@@ -2144,6 +2144,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
const int dst_code,
const VFPType src_type,
const int src_code,
Assembler::ConversionMode mode,
const Condition cond) {
ASSERT(src_type != dst_type);
int D, Vd, M, Vm;
......@@ -2162,7 +2163,7 @@ static Instr EncodeVCVT(const VFPType dst_type,
if (IsIntegerVFPType(dst_type)) {
opc2 = IsSignedVFPType(dst_type) ? 0x5 : 0x4;
sz = IsDoubleVFPType(src_type) ? 0x1 : 0x0;
op = 1; // round towards zero
op = mode;
} else {
ASSERT(IsIntegerVFPType(src_type));
opc2 = 0x0;
......@@ -2186,57 +2187,64 @@ static Instr EncodeVCVT(const VFPType dst_type,
void Assembler::vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), S32, src.code(), mode, cond));
}
void Assembler::vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), cond));
emit(EncodeVCVT(F32, dst.code(), S32, src.code(), mode, cond));
}
void Assembler::vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), U32, src.code(), mode, cond));
}
void Assembler::vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(S32, dst.code(), F64, src.code(), mode, cond));
}
void Assembler::vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(U32, dst.code(), F64, src.code(), mode, cond));
}
void Assembler::vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), cond));
emit(EncodeVCVT(F64, dst.code(), F32, src.code(), mode, cond));
}
void Assembler::vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode,
const Condition cond) {
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), cond));
emit(EncodeVCVT(F32, dst.code(), F64, src.code(), mode, cond));
}
......@@ -2329,6 +2337,16 @@ void Assembler::vcmp(const DwVfpRegister src1,
}
void Assembler::vmsr(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1110(23-20)| 0001 (19-16) |
// Rt(15-12) | 1010 (11-8) | 0(7) | 00 (6-5) | 1(4) | 0000(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xE*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
void Assembler::vmrs(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
......@@ -2339,7 +2357,6 @@ void Assembler::vmrs(Register dst, Condition cond) {
}
void Assembler::vsqrt(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond) {
......
......@@ -1008,26 +1008,37 @@ class Assembler : public Malloced {
void vmov(const Register dst,
const SwVfpRegister src,
const Condition cond = al);
enum ConversionMode {
FPSCRRounding = 0,
RoundToZero = 1
};
void vcvt_f64_s32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f32_s32(const SwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f64_u32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_s32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_u32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f64_f32(const DwVfpRegister dst,
const SwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vcvt_f32_f64(const SwVfpRegister dst,
const DwVfpRegister src,
ConversionMode mode = RoundToZero,
const Condition cond = al);
void vadd(const DwVfpRegister dst,
......@@ -1056,6 +1067,8 @@ class Assembler : public Malloced {
const Condition cond = al);
void vmrs(const Register dst,
const Condition cond = al);
void vmsr(const Register dst,
const Condition cond = al);
void vsqrt(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond = al);
......
......@@ -206,6 +206,13 @@ enum VFPRegPrecision {
kDoublePrecision = 1
};
// VFP rounding modes. See ARM DDI 0406B Page A2-29.
enum FPSCRRoundingModes {
RN, // Round to Nearest.
RP, // Round towards Plus Infinity.
RM, // Round towards Minus Infinity.
RZ // Round towards zero.
};
typedef int32_t instr_t;
......
......@@ -1988,9 +1988,9 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
// Not infinity or NaN simply convert to int.
if (IsElementTypeSigned(array_type)) {
__ vcvt_s32_f64(s0, d0, ne);
__ vcvt_s32_f64(s0, d0, Assembler::RoundToZero, ne);
} else {
__ vcvt_u32_f64(s0, d0, ne);
__ vcvt_u32_f64(s0, d0, Assembler::RoundToZero, ne);
}
__ vmov(r5, s0, ne);
......
......@@ -705,6 +705,7 @@ Simulator::Simulator() {
z_flag_FPSCR_ = false;
c_flag_FPSCR_ = false;
v_flag_FPSCR_ = false;
FPSCR_rounding_mode_ = RZ;
inv_op_vfp_flag_ = false;
div_zero_vfp_flag_ = false;
......@@ -2501,10 +2502,45 @@ void Simulator::DecodeTypeVFP(Instr* instr) {
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
// vmrs
if (instr->RtField() == 0xF)
uint32_t rt = instr->RtField();
if (rt == 0xF) {
Copy_FPSCR_to_APSR();
else
UNIMPLEMENTED(); // Not used by V8.
} else {
// Emulate FPSCR from the Simulator flags.
uint32_t fpscr = (n_flag_FPSCR_ << 31) |
(z_flag_FPSCR_ << 30) |
(c_flag_FPSCR_ << 29) |
(v_flag_FPSCR_ << 28) |
(inexact_vfp_flag_ << 4) |
(underflow_vfp_flag_ << 3) |
(overflow_vfp_flag_ << 2) |
(div_zero_vfp_flag_ << 1) |
(inv_op_vfp_flag_ << 0) |
(FPSCR_rounding_mode_ << 22);
set_register(rt, fpscr);
}
} else if ((instr->VLField() == 0x0) &&
(instr->VCField() == 0x0) &&
(instr->VAField() == 0x7) &&
(instr->Bits(19, 16) == 0x1)) {
// vmsr
uint32_t rt = instr->RtField();
if (rt == pc) {
UNREACHABLE();
} else {
uint32_t rt_value = get_register(rt);
n_flag_FPSCR_ = (rt_value >> 31) & 1;
z_flag_FPSCR_ = (rt_value >> 30) & 1;
c_flag_FPSCR_ = (rt_value >> 29) & 1;
v_flag_FPSCR_ = (rt_value >> 28) & 1;
inexact_vfp_flag_ = (rt_value >> 4) & 1;
underflow_vfp_flag_ = (rt_value >> 3) & 1;
overflow_vfp_flag_ = (rt_value >> 2) & 1;
div_zero_vfp_flag_ = (rt_value >> 1) & 1;
inv_op_vfp_flag_ = (rt_value >> 0) & 1;
FPSCR_rounding_mode_ =
static_cast<FPSCRRoundingModes>((rt_value >> 22) & 3);
}
} else {
UNIMPLEMENTED(); // Not used by V8.
}
......@@ -2605,29 +2641,71 @@ void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
if (to_integer) {
bool unsigned_integer = (instr->Bit(16) == 0);
FPSCRRoundingModes mode;
if (instr->Bit(7) != 1) {
// Only rounding towards zero supported.
UNIMPLEMENTED(); // Not used by V8.
// Use FPSCR defined rounding mode.
mode = FPSCR_rounding_mode_;
// Only RZ and RM modes are supported.
ASSERT((mode == RM) || (mode == RZ));
} else {
// VFP uses round towards zero by default.
mode = RZ;
}
int dst = instr->VFPDRegCode(kSinglePrecision);
int src = instr->VFPMRegCode(src_precision);
int32_t kMaxInt = v8::internal::kMaxInt;
int32_t kMinInt = v8::internal::kMinInt;
switch (mode) {
case RM:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
sint = sint > val ? sint - 1 : sint;
set_s_register_from_sinteger(dst, sint);
set_s_register_from_sinteger(dst, sint);
}
break;
case RZ:
if (src_precision == kDoublePrecision) {
double val = get_double_from_d_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
set_s_register_from_sinteger(dst, sint);
} else {
float val = get_float_from_s_register(src);
inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
int sint = unsigned_integer ? static_cast<uint32_t>(val) :
static_cast<int32_t>(val);
set_s_register_from_sinteger(dst, sint);
}
break;
default:
UNREACHABLE();
}
} else {
bool unsigned_integer = (instr->Bit(7) == 0);
......
......@@ -306,6 +306,9 @@ class Simulator {
bool c_flag_FPSCR_;
bool v_flag_FPSCR_;
// VFP rounding mode. See ARM DDI 0406B Page A2-29.
FPSCRRoundingModes FPSCR_rounding_mode_;
// VFP FP exception flags architecture state.
bool inv_op_vfp_flag_;
bool div_zero_vfp_flag_;
......
......@@ -397,4 +397,72 @@ TEST(6) {
}
}
static void TestRoundingMode(int32_t mode, double value, int expected) {
InitializeVM();
v8::HandleScope scope;
Assembler assm(NULL, 0);
__ vmrs(r1);
// Set custom FPSCR.
__ bic(r2, r1, Operand(((mode ^ 3) << 22) | 0xf));
__ orr(r2, r2, Operand(mode << 22));
__ vmsr(r2);
// Load value, convert, and move back result to r0.
__ vmov(d1, value);
__ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al);
__ vmov(r0, s0);
__ mov(pc, Operand(lr));
CodeDesc desc;
assm.GetCode(&desc);
Object* code = Heap::CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
CHECK(code->IsCode());
#ifdef DEBUG
Code::cast(code)->Print();
#endif
F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
int res = reinterpret_cast<int>(
CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
::printf("res = %d\n", res);
CHECK_EQ(expected, res);
}
TEST(7) {
// Test vfp rounding modes.
// See ARM DDI 0406B Page A2-29.
enum FPSCRRoungingMode {
RN, // Round to Nearest.
RP, // Round towards Plus Infinity.
RM, // Round towards Minus Infinity.
RZ // Round towards zero.
};
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
TestRoundingMode(RZ, 0.5, 0);
TestRoundingMode(RZ, -0.5, 0);
TestRoundingMode(RZ, 123.7, 123);
TestRoundingMode(RZ, -123.7, -123);
TestRoundingMode(RZ, 123456.2, 123456);
TestRoundingMode(RZ, -123456.2, -123456);
TestRoundingMode(RM, 0.5, 0);
TestRoundingMode(RM, -0.5, -1);
TestRoundingMode(RM, 123.7, 123);
TestRoundingMode(RM, -123.7, -124);
TestRoundingMode(RM, 123456.2, 123456);
TestRoundingMode(RM, -123456.2, -123457);
}
}
#undef __
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