Revision: 5790
Author: [email protected]
Date: Tue Nov 9 00:26:02 2010
Log: 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.
http://code.google.com/p/v8/source/detail?r=5790
Modified:
/branches/bleeding_edge/AUTHORS
/branches/bleeding_edge/src/arm/assembler-arm.cc
/branches/bleeding_edge/src/arm/assembler-arm.h
/branches/bleeding_edge/src/arm/constants-arm.h
/branches/bleeding_edge/src/arm/ic-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.h
/branches/bleeding_edge/test/cctest/test-assembler-arm.cc
=======================================
--- /branches/bleeding_edge/AUTHORS Thu Oct 14 04:39:48 2010
+++ /branches/bleeding_edge/AUTHORS Tue Nov 9 00:26:02 2010
@@ -9,6 +9,7 @@
Hewlett-Packard Development Company, LP
Alexander Botero-Lowry <[email protected]>
+Alexandre Rames <[email protected]>
Alexandre Vassalotti <[email protected]>
Andreas Anyuru <[email protected]>
Burcu Dogan <[email protected]>
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Thu Nov 4 08:30:04
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Nov 9 00:26:02
2010
@@ -2144,6 +2144,7 @@
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 @@
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 @@
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));
}
@@ -2327,6 +2335,16 @@
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
src1.code()*B12 | 0x5*B9 | B8 | B6);
}
+
+
+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) {
@@ -2337,7 +2355,6 @@
emit(cond | 0xE*B24 | 0xF*B20 | B16 |
dst.code()*B12 | 0xA*B8 | B4);
}
-
void Assembler::vsqrt(const DwVfpRegister dst,
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Thu Nov 4 08:39:06 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Tue Nov 9 00:26:02 2010
@@ -1008,26 +1008,37 @@
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 @@
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);
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.h Thu Oct 28 00:35:07 2010
+++ /branches/bleeding_edge/src/arm/constants-arm.h Tue Nov 9 00:26:02 2010
@@ -206,6 +206,13 @@
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;
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Mon Nov 1 01:55:40 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Tue Nov 9 00:26:02 2010
@@ -1988,9 +1988,9 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Oct 28 00:35:07
2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Nov 9 00:26:02
2010
@@ -705,6 +705,7 @@
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 @@
(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 @@
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);
-
- if (src_precision == kDoublePrecision) {
- double val = get_double_from_d_register(src);
-
- 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);
-
- int sint = unsigned_integer ? static_cast<uint32_t>(val) :
- static_cast<int32_t>(val);
-
- set_s_register_from_sinteger(dst, sint);
- }
+ 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);
+
+ inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val !=
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);
+
+ inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val !=
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);
+ }
+ 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);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.h Thu Oct 28 00:35:07 2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.h Tue Nov 9 00:26:02 2010
@@ -306,6 +306,9 @@
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_;
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Mon Oct 25
08:22:03 2010
+++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Tue Nov 9
00:26:02 2010
@@ -396,5 +396,73 @@
CHECK_EQ(382, res);
}
}
+
+
+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 __
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev