Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Unified Diff: src/arm/simulator-arm.cc

Issue 6368053: Implements DoubleToI on ARM. Refactor some VFP code at the same time and... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/arm/simulator-arm.h ('k') | src/arm/stub-cache-arm.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/arm/simulator-arm.cc
===================================================================
--- src/arm/simulator-arm.cc (revision 6620)
+++ src/arm/simulator-arm.cc (working copy)
@@ -2539,7 +2539,7 @@
(overflow_vfp_flag_ << 2) |
(div_zero_vfp_flag_ << 1) |
(inv_op_vfp_flag_ << 0) |
- (FPSCR_rounding_mode_ << 22);
+ (FPSCR_rounding_mode_);
set_register(rt, fpscr);
}
} else if ((instr->VLValue() == 0x0) &&
@@ -2562,7 +2562,7 @@
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);
+ static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
}
} else {
UNIMPLEMENTED(); // Not used by V8.
@@ -2651,87 +2651,135 @@
}
}
+bool get_inv_op_vfp_flag(VFPRoundingMode mode,
+ double val,
+ bool unsigned_) {
+ ASSERT((mode == RN) || (mode == RM) || (mode == RZ));
+ double max_uint = static_cast<double>(0xffffffffu);
+ double max_int = static_cast<double>(kMaxInt);
+ double min_int = static_cast<double>(kMinInt);
+ // Check for NaN.
+ if (val != val) {
+ return true;
+ }
+
+ // Check for overflow. This code works because 32bit integers can be
+ // exactly represented by ieee-754 64bit floating-point values.
+ switch (mode) {
+ case RN:
+ return unsigned_ ? (val >= (max_uint + 0.5)) ||
+ (val < -0.5)
+ : (val >= (max_int + 0.5)) ||
+ (val < (min_int - 0.5));
+
+ case RM:
+ return unsigned_ ? (val >= (max_uint + 1.0)) ||
+ (val < 0)
+ : (val >= (max_int + 1.0)) ||
+ (val < min_int);
+
+ case RZ:
+ return unsigned_ ? (val >= (max_uint + 1.0)) ||
+ (val <= -1)
+ : (val >= (max_int + 1.0)) ||
+ (val <= (min_int - 1.0));
+ default:
+ UNREACHABLE();
+ return true;
+ }
+}
+
+
+// We call this function only if we had a vfp invalid exception.
+// It returns the correct saturated value.
+int VFPConversionSaturate(double val, bool unsigned_res) {
+ if (val != val) {
+ return 0;
+ } else {
+ if (unsigned_res) {
+ return (val < 0) ? 0 : 0xffffffffu;
+ } else {
+ return (val < 0) ? kMinInt : kMaxInt;
+ }
+ }
+}
+
+
void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
- ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
+ ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
+ (instr->Bits(27, 23) == 0x1D));
ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
(((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
// Conversion between floating-point and integer.
bool to_integer = (instr->Bit(18) == 1);
- VFPRegPrecision src_precision = kSinglePrecision;
- if (instr->SzValue() == 1) {
- src_precision = kDoublePrecision;
- }
+ VFPRegPrecision src_precision = (instr->SzValue() == 1) ? kDoublePrecision
+ : kSinglePrecision;
if (to_integer) {
- bool unsigned_integer = (instr->Bit(16) == 0);
- FPSCRRoundingModes mode;
- if (instr->Bit(7) != 1) {
- // 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;
- }
+ // We are playing with code close to the C++ standard's limits below,
+ // hence the very simple code and heavy checks.
+ //
+ // Note:
+ // C++ defines default type casting from floating point to integer as
+ // (close to) rounding toward zero ("fractional part discarded").
int dst = instr->VFPDRegValue(kSinglePrecision);
int src = instr->VFPMRegValue(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);
- inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+ // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
+ // mode or the default Round to Zero mode.
+ VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_
+ : RZ;
+ ASSERT((mode == RM) || (mode == RZ) || (mode == RN));
- int sint = unsigned_integer ? static_cast<uint32_t>(val) :
- static_cast<int32_t>(val);
- sint = sint > val ? sint - 1 : sint;
+ bool unsigned_integer = (instr->Bit(16) == 0);
+ bool double_precision = (src_precision == kDoublePrecision);
- set_s_register_from_sinteger(dst, sint);
- } else {
- float val = get_float_from_s_register(src);
+ double val = double_precision ? get_double_from_d_register(src)
+ : get_float_from_s_register(src);
- inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+ int temp = 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;
+ inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
- set_s_register_from_sinteger(dst, sint);
+ if (inv_op_vfp_flag_) {
+ temp = VFPConversionSaturate(val, unsigned_integer);
+ } else {
+ switch (mode) {
+ case RN: {
+ double abs_diff =
+ unsigned_integer ? fabs(val - static_cast<uint32_t>(temp))
+ : fabs(val - temp);
+ int val_sign = (val > 0) ? 1 : -1;
+ if (abs_diff > 0.5) {
+ temp += val_sign;
+ } else if (abs_diff == 0.5) {
+ // Round to even if exactly halfway.
+ temp = ((temp % 2) == 0) ? temp : temp + val_sign;
+ }
+ break;
}
- 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);
+ case RM:
+ temp = temp > val ? temp - 1 : temp;
+ break;
- int sint = unsigned_integer ? static_cast<uint32_t>(val) :
- static_cast<int32_t>(val);
+ case RZ:
+ // Nothing to do.
+ break;
- set_s_register_from_sinteger(dst, sint);
- } else {
- float val = get_float_from_s_register(src);
+ default:
+ UNREACHABLE();
+ }
+ }
- inv_op_vfp_flag_ = (val > kMaxInt) || (val < kMinInt) || (val != val);
+ // Update the destination register.
+ set_s_register_from_sinteger(dst, temp);
- 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);
« no previous file with comments | « src/arm/simulator-arm.h ('k') | src/arm/stub-cache-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698