michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef vm_NumericConversions_h michael@0: #define vm_NumericConversions_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Casting.h" michael@0: #include "mozilla/FloatingPoint.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: michael@0: #include michael@0: michael@0: namespace js { michael@0: michael@0: namespace detail { michael@0: michael@0: /* michael@0: * Convert a double value to ResultType (an unsigned integral type) using michael@0: * ECMAScript-style semantics (that is, in like manner to how ECMAScript's michael@0: * ToInt32 converts to int32_t). michael@0: * michael@0: * If d is infinite or NaN, return 0. michael@0: * Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType michael@0: * value congruent to d2 mod 2**(bit width of ResultType). michael@0: * michael@0: * The algorithm below is inspired by that found in michael@0: * michael@0: * but has been generalized to all integer widths. michael@0: */ michael@0: template michael@0: inline ResultType michael@0: ToUintWidth(double d) michael@0: { michael@0: static_assert(mozilla::IsUnsigned::value, michael@0: "ResultType must be an unsigned type"); michael@0: michael@0: uint64_t bits = mozilla::BitwiseCast(d); michael@0: unsigned DoubleExponentShift = mozilla::FloatingPoint::ExponentShift; michael@0: michael@0: // Extract the exponent component. (Be careful here! It's not technically michael@0: // the exponent in NaN, infinities, and subnormals.) michael@0: int_fast16_t exp = michael@0: int_fast16_t((bits & mozilla::FloatingPoint::ExponentBits) >> DoubleExponentShift) - michael@0: int_fast16_t(mozilla::FloatingPoint::ExponentBias); michael@0: michael@0: // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This michael@0: // also handles subnormals.) michael@0: if (exp < 0) michael@0: return 0; michael@0: michael@0: uint_fast16_t exponent = mozilla::SafeCast(exp); michael@0: michael@0: // If the exponent is greater than or equal to the bits of precision of a michael@0: // double plus ResultType's width, the number is either infinite, NaN, or michael@0: // too large to have lower-order bits in the congruent value. (Example: michael@0: // 2**84 is exactly representable as a double. The next exact double is michael@0: // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies michael@0: // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. michael@0: const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); michael@0: if (exponent >= DoubleExponentShift + ResultWidth) michael@0: return 0; michael@0: michael@0: // The significand contains the bits that will determine the final result. michael@0: // Shift those bits left or right, according to the exponent, to their michael@0: // locations in the unsigned binary representation of floor(abs(d)). michael@0: static_assert(sizeof(ResultType) <= sizeof(uint64_t), michael@0: "Left-shifting below would lose upper bits"); michael@0: ResultType result = (exponent > DoubleExponentShift) michael@0: ? ResultType(bits << (exponent - DoubleExponentShift)) michael@0: : ResultType(bits >> (DoubleExponentShift - exponent)); michael@0: michael@0: // Two further complications remain. First, |result| may contain bogus michael@0: // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding michael@0: // subnormals, but we already handled those) have an implicit leading 1 michael@0: // which may affect the final result. michael@0: // michael@0: // It may appear that there's complexity here depending on how ResultWidth michael@0: // and DoubleExponentShift relate, but it turns out there's not. michael@0: // michael@0: // Assume ResultWidth < DoubleExponentShift: michael@0: // Only right-shifts leave bogus bits in |result|. For this to happen, michael@0: // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying michael@0: // |exponent < ResultWidth|. michael@0: // The implicit leading bit only matters if it appears in the final michael@0: // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies michael@0: // |exponent < ResultWidth|. michael@0: // Otherwise assume ResultWidth >= DoubleExponentShift: michael@0: // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves michael@0: // bogus bits in |result|. This implies |exponent < ResultWidth|. Any michael@0: // right-shift less than |ResultWidth| does too, which implies michael@0: // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, michael@0: // |exponent| is negative, but we excluded that above. So bogus bits michael@0: // need only |exponent < ResultWidth|. michael@0: // The implicit leading bit matters identically to the other case, so michael@0: // again, |exponent < ResultWidth|. michael@0: if (exponent < ResultWidth) { michael@0: ResultType implicitOne = ResultType(1) << exponent; michael@0: result &= implicitOne - 1; // remove bogus bits michael@0: result += implicitOne; // add the implicit bit michael@0: } michael@0: michael@0: // Compute the congruent value in the signed range. michael@0: return (bits & mozilla::FloatingPoint::SignBit) ? ~result + 1 : result; michael@0: } michael@0: michael@0: template michael@0: inline ResultType michael@0: ToIntWidth(double d) michael@0: { michael@0: static_assert(mozilla::IsSigned::value, michael@0: "ResultType must be a signed type"); michael@0: michael@0: const ResultType MaxValue = (1ULL << (CHAR_BIT * sizeof(ResultType) - 1)) - 1; michael@0: const ResultType MinValue = -MaxValue - 1; michael@0: michael@0: typedef typename mozilla::MakeUnsigned::Type UnsignedResult; michael@0: UnsignedResult u = ToUintWidth(d); michael@0: if (u <= UnsignedResult(MaxValue)) michael@0: return static_cast(u); michael@0: return (MinValue + static_cast(u - MaxValue)) - 1; michael@0: } michael@0: michael@0: } /* namespace detail */ michael@0: michael@0: /* ES5 9.5 ToInt32 (specialized for doubles). */ michael@0: inline int32_t michael@0: ToInt32(double d) michael@0: { michael@0: #if defined (__arm__) && defined (__GNUC__) michael@0: int32_t i; michael@0: uint32_t tmp0; michael@0: uint32_t tmp1; michael@0: uint32_t tmp2; michael@0: asm ( michael@0: // We use a pure integer solution here. In the 'softfp' ABI, the argument michael@0: // will start in r0 and r1, and VFP can't do all of the necessary ECMA michael@0: // conversions by itself so some integer code will be required anyway. A michael@0: // hybrid solution is faster on A9, but this pure integer solution is michael@0: // notably faster for A8. michael@0: michael@0: // %0 is the result register, and may alias either of the %[QR]1 registers. michael@0: // %Q4 holds the lower part of the mantissa. michael@0: // %R4 holds the sign, exponent, and the upper part of the mantissa. michael@0: // %1, %2 and %3 are used as temporary values. michael@0: michael@0: // Extract the exponent. michael@0: " mov %1, %R4, LSR #20\n" michael@0: " bic %1, %1, #(1 << 11)\n" // Clear the sign. michael@0: michael@0: // Set the implicit top bit of the mantissa. This clobbers a bit of the michael@0: // exponent, but we have already extracted that. michael@0: " orr %R4, %R4, #(1 << 20)\n" michael@0: michael@0: // Special Cases michael@0: // We should return zero in the following special cases: michael@0: // - Exponent is 0x000 - 1023: +/-0 or subnormal. michael@0: // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN michael@0: // - This case is implicitly handled by the standard code path anyway, michael@0: // as shifting the mantissa up by the exponent will result in '0'. michael@0: // michael@0: // The result is composed of the mantissa, prepended with '1' and michael@0: // bit-shifted left by the (decoded) exponent. Note that because the r1[20] michael@0: // is the bit with value '1', r1 is effectively already shifted (left) by michael@0: // 20 bits, and r0 is already shifted by 52 bits. michael@0: michael@0: // Adjust the exponent to remove the encoding offset. If the decoded michael@0: // exponent is negative, quickly bail out with '0' as such values round to michael@0: // zero anyway. This also catches +/-0 and subnormals. michael@0: " sub %1, %1, #0xff\n" michael@0: " subs %1, %1, #0x300\n" michael@0: " bmi 8f\n" michael@0: michael@0: // %1 = (decoded) exponent >= 0 michael@0: // %R4 = upper mantissa and sign michael@0: michael@0: // ---- Lower Mantissa ---- michael@0: " subs %3, %1, #52\n" // Calculate exp-52 michael@0: " bmi 1f\n" michael@0: michael@0: // Shift r0 left by exp-52. michael@0: // Ensure that we don't overflow ARM's 8-bit shift operand range. michael@0: // We need to handle anything up to an 11-bit value here as we know that michael@0: // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero michael@0: // anyway, so as long as we don't touch the bottom 5 bits, we can use michael@0: // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. michael@0: " bic %2, %3, #0xff\n" michael@0: " orr %3, %3, %2, LSR #3\n" michael@0: // We can now perform a straight shift, avoiding the need for any michael@0: // conditional instructions or extra branches. michael@0: " mov %Q4, %Q4, LSL %3\n" michael@0: " b 2f\n" michael@0: "1:\n" // Shift r0 right by 52-exp. michael@0: // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp michael@0: // will always be a valid shift and we can sk%3 the range check for this case. michael@0: " rsb %3, %1, #52\n" michael@0: " mov %Q4, %Q4, LSR %3\n" michael@0: michael@0: // %1 = (decoded) exponent michael@0: // %R4 = upper mantissa and sign michael@0: // %Q4 = partially-converted integer michael@0: michael@0: "2:\n" michael@0: // ---- Upper Mantissa ---- michael@0: // This is much the same as the lower mantissa, with a few different michael@0: // boundary checks and some masking to hide the exponent & sign bit in the michael@0: // upper word. michael@0: // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift michael@0: // it left more to remove the sign and exponent so it is effectively michael@0: // pre-shifted by 31 bits. michael@0: " subs %3, %1, #31\n" // Calculate exp-31 michael@0: " mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. michael@0: " bmi 3f\n" michael@0: michael@0: // Shift %R4 left by exp-31. michael@0: // Avoid overflowing the 8-bit shift range, as before. michael@0: " bic %2, %3, #0xff\n" michael@0: " orr %3, %3, %2, LSR #3\n" michael@0: // Perform the shift. michael@0: " mov %2, %1, LSL %3\n" michael@0: " b 4f\n" michael@0: "3:\n" // Shift r1 right by 31-exp. michael@0: // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp michael@0: // will always be a valid shift and we can skip the range check for this case. michael@0: " rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) michael@0: " mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". michael@0: michael@0: // %Q4 = partially-converted integer (lower) michael@0: // %R4 = upper mantissa and sign michael@0: // %2 = partially-converted integer (upper) michael@0: michael@0: "4:\n" michael@0: // Combine the converted parts. michael@0: " orr %Q4, %Q4, %2\n" michael@0: // Negate the result if we have to, and move it to %0 in the process. To michael@0: // avoid conditionals, we can do this by inverting on %R4[31], then adding michael@0: // %R4[31]>>31. michael@0: " eor %Q4, %Q4, %R4, ASR #31\n" michael@0: " add %0, %Q4, %R4, LSR #31\n" michael@0: " b 9f\n" michael@0: "8:\n" michael@0: // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that michael@0: // will result in a conversion of '0'. michael@0: " mov %0, #0\n" michael@0: "9:\n" michael@0: : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), "=&r" (d) michael@0: : "4" (d) michael@0: : "cc" michael@0: ); michael@0: return i; michael@0: #else michael@0: return detail::ToIntWidth(d); michael@0: #endif michael@0: } michael@0: michael@0: /* ES5 9.6 (specialized for doubles). */ michael@0: inline uint32_t michael@0: ToUint32(double d) michael@0: { michael@0: return detail::ToUintWidth(d); michael@0: } michael@0: michael@0: /* WEBIDL 4.2.10 */ michael@0: inline int64_t michael@0: ToInt64(double d) michael@0: { michael@0: return detail::ToIntWidth(d); michael@0: } michael@0: michael@0: /* WEBIDL 4.2.11 */ michael@0: inline uint64_t michael@0: ToUint64(double d) michael@0: { michael@0: return detail::ToUintWidth(d); michael@0: } michael@0: michael@0: /* ES5 9.4 ToInteger (specialized for doubles). */ michael@0: inline double michael@0: ToInteger(double d) michael@0: { michael@0: if (d == 0) michael@0: return d; michael@0: michael@0: if (!mozilla::IsFinite(d)) { michael@0: if (mozilla::IsNaN(d)) michael@0: return 0; michael@0: return d; michael@0: } michael@0: michael@0: return d < 0 ? ceil(d) : floor(d); michael@0: } michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* vm_NumericConversions_h */