|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef vm_NumericConversions_h |
|
8 #define vm_NumericConversions_h |
|
9 |
|
10 #include "mozilla/Assertions.h" |
|
11 #include "mozilla/Casting.h" |
|
12 #include "mozilla/FloatingPoint.h" |
|
13 #include "mozilla/TypeTraits.h" |
|
14 |
|
15 #include <math.h> |
|
16 |
|
17 namespace js { |
|
18 |
|
19 namespace detail { |
|
20 |
|
21 /* |
|
22 * Convert a double value to ResultType (an unsigned integral type) using |
|
23 * ECMAScript-style semantics (that is, in like manner to how ECMAScript's |
|
24 * ToInt32 converts to int32_t). |
|
25 * |
|
26 * If d is infinite or NaN, return 0. |
|
27 * Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType |
|
28 * value congruent to d2 mod 2**(bit width of ResultType). |
|
29 * |
|
30 * The algorithm below is inspired by that found in |
|
31 * <http://trac.webkit.org/changeset/67825/trunk/JavaScriptCore/runtime/JSValue.cpp> |
|
32 * but has been generalized to all integer widths. |
|
33 */ |
|
34 template<typename ResultType> |
|
35 inline ResultType |
|
36 ToUintWidth(double d) |
|
37 { |
|
38 static_assert(mozilla::IsUnsigned<ResultType>::value, |
|
39 "ResultType must be an unsigned type"); |
|
40 |
|
41 uint64_t bits = mozilla::BitwiseCast<uint64_t>(d); |
|
42 unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::ExponentShift; |
|
43 |
|
44 // Extract the exponent component. (Be careful here! It's not technically |
|
45 // the exponent in NaN, infinities, and subnormals.) |
|
46 int_fast16_t exp = |
|
47 int_fast16_t((bits & mozilla::FloatingPoint<double>::ExponentBits) >> DoubleExponentShift) - |
|
48 int_fast16_t(mozilla::FloatingPoint<double>::ExponentBias); |
|
49 |
|
50 // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This |
|
51 // also handles subnormals.) |
|
52 if (exp < 0) |
|
53 return 0; |
|
54 |
|
55 uint_fast16_t exponent = mozilla::SafeCast<uint_fast16_t>(exp); |
|
56 |
|
57 // If the exponent is greater than or equal to the bits of precision of a |
|
58 // double plus ResultType's width, the number is either infinite, NaN, or |
|
59 // too large to have lower-order bits in the congruent value. (Example: |
|
60 // 2**84 is exactly representable as a double. The next exact double is |
|
61 // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies |
|
62 // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. |
|
63 const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); |
|
64 if (exponent >= DoubleExponentShift + ResultWidth) |
|
65 return 0; |
|
66 |
|
67 // The significand contains the bits that will determine the final result. |
|
68 // Shift those bits left or right, according to the exponent, to their |
|
69 // locations in the unsigned binary representation of floor(abs(d)). |
|
70 static_assert(sizeof(ResultType) <= sizeof(uint64_t), |
|
71 "Left-shifting below would lose upper bits"); |
|
72 ResultType result = (exponent > DoubleExponentShift) |
|
73 ? ResultType(bits << (exponent - DoubleExponentShift)) |
|
74 : ResultType(bits >> (DoubleExponentShift - exponent)); |
|
75 |
|
76 // Two further complications remain. First, |result| may contain bogus |
|
77 // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding |
|
78 // subnormals, but we already handled those) have an implicit leading 1 |
|
79 // which may affect the final result. |
|
80 // |
|
81 // It may appear that there's complexity here depending on how ResultWidth |
|
82 // and DoubleExponentShift relate, but it turns out there's not. |
|
83 // |
|
84 // Assume ResultWidth < DoubleExponentShift: |
|
85 // Only right-shifts leave bogus bits in |result|. For this to happen, |
|
86 // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying |
|
87 // |exponent < ResultWidth|. |
|
88 // The implicit leading bit only matters if it appears in the final |
|
89 // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies |
|
90 // |exponent < ResultWidth|. |
|
91 // Otherwise assume ResultWidth >= DoubleExponentShift: |
|
92 // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves |
|
93 // bogus bits in |result|. This implies |exponent < ResultWidth|. Any |
|
94 // right-shift less than |ResultWidth| does too, which implies |
|
95 // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, |
|
96 // |exponent| is negative, but we excluded that above. So bogus bits |
|
97 // need only |exponent < ResultWidth|. |
|
98 // The implicit leading bit matters identically to the other case, so |
|
99 // again, |exponent < ResultWidth|. |
|
100 if (exponent < ResultWidth) { |
|
101 ResultType implicitOne = ResultType(1) << exponent; |
|
102 result &= implicitOne - 1; // remove bogus bits |
|
103 result += implicitOne; // add the implicit bit |
|
104 } |
|
105 |
|
106 // Compute the congruent value in the signed range. |
|
107 return (bits & mozilla::FloatingPoint<double>::SignBit) ? ~result + 1 : result; |
|
108 } |
|
109 |
|
110 template<typename ResultType> |
|
111 inline ResultType |
|
112 ToIntWidth(double d) |
|
113 { |
|
114 static_assert(mozilla::IsSigned<ResultType>::value, |
|
115 "ResultType must be a signed type"); |
|
116 |
|
117 const ResultType MaxValue = (1ULL << (CHAR_BIT * sizeof(ResultType) - 1)) - 1; |
|
118 const ResultType MinValue = -MaxValue - 1; |
|
119 |
|
120 typedef typename mozilla::MakeUnsigned<ResultType>::Type UnsignedResult; |
|
121 UnsignedResult u = ToUintWidth<UnsignedResult>(d); |
|
122 if (u <= UnsignedResult(MaxValue)) |
|
123 return static_cast<ResultType>(u); |
|
124 return (MinValue + static_cast<ResultType>(u - MaxValue)) - 1; |
|
125 } |
|
126 |
|
127 } /* namespace detail */ |
|
128 |
|
129 /* ES5 9.5 ToInt32 (specialized for doubles). */ |
|
130 inline int32_t |
|
131 ToInt32(double d) |
|
132 { |
|
133 #if defined (__arm__) && defined (__GNUC__) |
|
134 int32_t i; |
|
135 uint32_t tmp0; |
|
136 uint32_t tmp1; |
|
137 uint32_t tmp2; |
|
138 asm ( |
|
139 // We use a pure integer solution here. In the 'softfp' ABI, the argument |
|
140 // will start in r0 and r1, and VFP can't do all of the necessary ECMA |
|
141 // conversions by itself so some integer code will be required anyway. A |
|
142 // hybrid solution is faster on A9, but this pure integer solution is |
|
143 // notably faster for A8. |
|
144 |
|
145 // %0 is the result register, and may alias either of the %[QR]1 registers. |
|
146 // %Q4 holds the lower part of the mantissa. |
|
147 // %R4 holds the sign, exponent, and the upper part of the mantissa. |
|
148 // %1, %2 and %3 are used as temporary values. |
|
149 |
|
150 // Extract the exponent. |
|
151 " mov %1, %R4, LSR #20\n" |
|
152 " bic %1, %1, #(1 << 11)\n" // Clear the sign. |
|
153 |
|
154 // Set the implicit top bit of the mantissa. This clobbers a bit of the |
|
155 // exponent, but we have already extracted that. |
|
156 " orr %R4, %R4, #(1 << 20)\n" |
|
157 |
|
158 // Special Cases |
|
159 // We should return zero in the following special cases: |
|
160 // - Exponent is 0x000 - 1023: +/-0 or subnormal. |
|
161 // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN |
|
162 // - This case is implicitly handled by the standard code path anyway, |
|
163 // as shifting the mantissa up by the exponent will result in '0'. |
|
164 // |
|
165 // The result is composed of the mantissa, prepended with '1' and |
|
166 // bit-shifted left by the (decoded) exponent. Note that because the r1[20] |
|
167 // is the bit with value '1', r1 is effectively already shifted (left) by |
|
168 // 20 bits, and r0 is already shifted by 52 bits. |
|
169 |
|
170 // Adjust the exponent to remove the encoding offset. If the decoded |
|
171 // exponent is negative, quickly bail out with '0' as such values round to |
|
172 // zero anyway. This also catches +/-0 and subnormals. |
|
173 " sub %1, %1, #0xff\n" |
|
174 " subs %1, %1, #0x300\n" |
|
175 " bmi 8f\n" |
|
176 |
|
177 // %1 = (decoded) exponent >= 0 |
|
178 // %R4 = upper mantissa and sign |
|
179 |
|
180 // ---- Lower Mantissa ---- |
|
181 " subs %3, %1, #52\n" // Calculate exp-52 |
|
182 " bmi 1f\n" |
|
183 |
|
184 // Shift r0 left by exp-52. |
|
185 // Ensure that we don't overflow ARM's 8-bit shift operand range. |
|
186 // We need to handle anything up to an 11-bit value here as we know that |
|
187 // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero |
|
188 // anyway, so as long as we don't touch the bottom 5 bits, we can use |
|
189 // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. |
|
190 " bic %2, %3, #0xff\n" |
|
191 " orr %3, %3, %2, LSR #3\n" |
|
192 // We can now perform a straight shift, avoiding the need for any |
|
193 // conditional instructions or extra branches. |
|
194 " mov %Q4, %Q4, LSL %3\n" |
|
195 " b 2f\n" |
|
196 "1:\n" // Shift r0 right by 52-exp. |
|
197 // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp |
|
198 // will always be a valid shift and we can sk%3 the range check for this case. |
|
199 " rsb %3, %1, #52\n" |
|
200 " mov %Q4, %Q4, LSR %3\n" |
|
201 |
|
202 // %1 = (decoded) exponent |
|
203 // %R4 = upper mantissa and sign |
|
204 // %Q4 = partially-converted integer |
|
205 |
|
206 "2:\n" |
|
207 // ---- Upper Mantissa ---- |
|
208 // This is much the same as the lower mantissa, with a few different |
|
209 // boundary checks and some masking to hide the exponent & sign bit in the |
|
210 // upper word. |
|
211 // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift |
|
212 // it left more to remove the sign and exponent so it is effectively |
|
213 // pre-shifted by 31 bits. |
|
214 " subs %3, %1, #31\n" // Calculate exp-31 |
|
215 " mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. |
|
216 " bmi 3f\n" |
|
217 |
|
218 // Shift %R4 left by exp-31. |
|
219 // Avoid overflowing the 8-bit shift range, as before. |
|
220 " bic %2, %3, #0xff\n" |
|
221 " orr %3, %3, %2, LSR #3\n" |
|
222 // Perform the shift. |
|
223 " mov %2, %1, LSL %3\n" |
|
224 " b 4f\n" |
|
225 "3:\n" // Shift r1 right by 31-exp. |
|
226 // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp |
|
227 // will always be a valid shift and we can skip the range check for this case. |
|
228 " rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) |
|
229 " mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". |
|
230 |
|
231 // %Q4 = partially-converted integer (lower) |
|
232 // %R4 = upper mantissa and sign |
|
233 // %2 = partially-converted integer (upper) |
|
234 |
|
235 "4:\n" |
|
236 // Combine the converted parts. |
|
237 " orr %Q4, %Q4, %2\n" |
|
238 // Negate the result if we have to, and move it to %0 in the process. To |
|
239 // avoid conditionals, we can do this by inverting on %R4[31], then adding |
|
240 // %R4[31]>>31. |
|
241 " eor %Q4, %Q4, %R4, ASR #31\n" |
|
242 " add %0, %Q4, %R4, LSR #31\n" |
|
243 " b 9f\n" |
|
244 "8:\n" |
|
245 // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that |
|
246 // will result in a conversion of '0'. |
|
247 " mov %0, #0\n" |
|
248 "9:\n" |
|
249 : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), "=&r" (d) |
|
250 : "4" (d) |
|
251 : "cc" |
|
252 ); |
|
253 return i; |
|
254 #else |
|
255 return detail::ToIntWidth<int32_t>(d); |
|
256 #endif |
|
257 } |
|
258 |
|
259 /* ES5 9.6 (specialized for doubles). */ |
|
260 inline uint32_t |
|
261 ToUint32(double d) |
|
262 { |
|
263 return detail::ToUintWidth<uint32_t>(d); |
|
264 } |
|
265 |
|
266 /* WEBIDL 4.2.10 */ |
|
267 inline int64_t |
|
268 ToInt64(double d) |
|
269 { |
|
270 return detail::ToIntWidth<int64_t>(d); |
|
271 } |
|
272 |
|
273 /* WEBIDL 4.2.11 */ |
|
274 inline uint64_t |
|
275 ToUint64(double d) |
|
276 { |
|
277 return detail::ToUintWidth<uint64_t>(d); |
|
278 } |
|
279 |
|
280 /* ES5 9.4 ToInteger (specialized for doubles). */ |
|
281 inline double |
|
282 ToInteger(double d) |
|
283 { |
|
284 if (d == 0) |
|
285 return d; |
|
286 |
|
287 if (!mozilla::IsFinite(d)) { |
|
288 if (mozilla::IsNaN(d)) |
|
289 return 0; |
|
290 return d; |
|
291 } |
|
292 |
|
293 return d < 0 ? ceil(d) : floor(d); |
|
294 } |
|
295 |
|
296 } /* namespace js */ |
|
297 |
|
298 #endif /* vm_NumericConversions_h */ |