1 // Copyright 2018 Ulf Adams
2 //
3 // The contents of this file may be used under the terms of the Apache License,
4 // Version 2.0.
5 //
6 // (See accompanying file LICENSE-Apache or copy at
7 // http://www.apache.org/licenses/LICENSE-2.0)
8 //
9 // Alternatively, the contents of this file may be used under the terms of
10 // the Boost Software License, Version 1.0.
11 // (See accompanying file LICENSE-Boost or copy at
12 // https://www.boost.org/LICENSE_1_0.txt)
13 //
14 // Unless required by applicable law or agreed to in writing, this software
15 // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 // KIND, either express or implied.
17 #ifndef RYU_D2S_INTRINSICS_H
18 #define RYU_D2S_INTRINSICS_H
19
20
21 // Defines RYU_32_BIT_PLATFORM if applicable.
22
23 // ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined.
24 // Let's do the same for now.
25 #if defined(__SIZEOF_INT128__) && !defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS)
26 #define HAS_UINT128
27 #elif defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64)
28 #define HAS_64_BIT_INTRINSICS
29 #endif
30
31 #if defined(HAS_64_BIT_INTRINSICS)
32
33
umul128(const uint64_t a,const uint64_t b,uint64_t * const productHi)34 static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
35 return _umul128(a, b, productHi);
36 }
37
38 // Returns the lower 64 bits of (hi*2^64 + lo) >> dist, with 0 < dist < 64.
shiftright128(const uint64_t lo,const uint64_t hi,const uint32_t dist)39 static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
40 // For the __shiftright128 intrinsic, the shift value is always
41 // modulo 64.
42 // In the current implementation of the double-precision version
43 // of Ryu, the shift value is always < 64. (In the case
44 // RYU_OPTIMIZE_SIZE == 0, the shift value is in the range [49, 58].
45 // Otherwise in the range [2, 59].)
46 // However, this function is now also called by s2d, which requires supporting
47 // the larger shift range (TODO: what is the actual range?).
48 // Check this here in case a future change requires larger shift
49 // values. In this case this function needs to be adjusted.
50 assert(dist < 64);
51 return __shiftright128(lo, hi, (unsigned char) dist);
52 }
53
54 #else // defined(HAS_64_BIT_INTRINSICS)
55
umul128(const uint64_t a,const uint64_t b,uint64_t * const productHi)56 static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
57 // The casts here help MSVC to avoid calls to the __allmul library function.
58 const uint32_t aLo = (uint32_t)a;
59 const uint32_t aHi = (uint32_t)(a >> 32);
60 const uint32_t bLo = (uint32_t)b;
61 const uint32_t bHi = (uint32_t)(b >> 32);
62
63 const uint64_t b00 = (uint64_t)aLo * bLo;
64 const uint64_t b01 = (uint64_t)aLo * bHi;
65 const uint64_t b10 = (uint64_t)aHi * bLo;
66 const uint64_t b11 = (uint64_t)aHi * bHi;
67
68 const uint32_t b00Lo = (uint32_t)b00;
69 const uint32_t b00Hi = (uint32_t)(b00 >> 32);
70
71 const uint64_t mid1 = b10 + b00Hi;
72 const uint32_t mid1Lo = (uint32_t)(mid1);
73 const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
74
75 const uint64_t mid2 = b01 + mid1Lo;
76 const uint32_t mid2Lo = (uint32_t)(mid2);
77 const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
78
79 const uint64_t pHi = b11 + mid1Hi + mid2Hi;
80 const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
81
82 *productHi = pHi;
83 return pLo;
84 }
85
shiftright128(const uint64_t lo,const uint64_t hi,const uint32_t dist)86 static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
87 // We don't need to handle the case dist >= 64 here (see above).
88 assert(dist < 64);
89 assert(dist > 0);
90 return (hi << (64 - dist)) | (lo >> dist);
91 }
92
93 #endif // defined(HAS_64_BIT_INTRINSICS)
94
95 #if defined(RYU_32_BIT_PLATFORM)
96
97 // Returns the high 64 bits of the 128-bit product of a and b.
umulh(const uint64_t a,const uint64_t b)98 static inline uint64_t umulh(const uint64_t a, const uint64_t b) {
99 // Reuse the umul128 implementation.
100 // Optimizers will likely eliminate the instructions used to compute the
101 // low part of the product.
102 uint64_t hi;
103 umul128(a, b, &hi);
104 return hi;
105 }
106
107 // On 32-bit platforms, compilers typically generate calls to library
108 // functions for 64-bit divisions, even if the divisor is a constant.
109 //
110 // E.g.:
111 // https://bugs.llvm.org/show_bug.cgi?id=37932
112 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=17958
113 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37443
114 //
115 // The functions here perform division-by-constant using multiplications
116 // in the same way as 64-bit compilers would do.
117 //
118 // NB:
119 // The multipliers and shift values are the ones generated by clang x64
120 // for expressions like x/5, x/10, etc.
121
div5(const uint64_t x)122 static inline uint64_t div5(const uint64_t x) {
123 return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 2;
124 }
125
div10(const uint64_t x)126 static inline uint64_t div10(const uint64_t x) {
127 return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 3;
128 }
129
div100(const uint64_t x)130 static inline uint64_t div100(const uint64_t x) {
131 return umulh(x >> 2, 0x28F5C28F5C28F5C3u) >> 2;
132 }
133
div1e8(const uint64_t x)134 static inline uint64_t div1e8(const uint64_t x) {
135 return umulh(x, 0xABCC77118461CEFDu) >> 26;
136 }
137
div1e9(const uint64_t x)138 static inline uint64_t div1e9(const uint64_t x) {
139 return umulh(x >> 9, 0x44B82FA09B5A53u) >> 11;
140 }
141
mod1e9(const uint64_t x)142 static inline uint32_t mod1e9(const uint64_t x) {
143 // Avoid 64-bit math as much as possible.
144 // Returning (uint32_t) (x - 1000000000 * div1e9(x)) would
145 // perform 32x64-bit multiplication and 64-bit subtraction.
146 // x and 1000000000 * div1e9(x) are guaranteed to differ by
147 // less than 10^9, so their highest 32 bits must be identical,
148 // so we can truncate both sides to uint32_t before subtracting.
149 // We can also simplify (uint32_t) (1000000000 * div1e9(x)).
150 // We can truncate before multiplying instead of after, as multiplying
151 // the highest 32 bits of div1e9(x) can't affect the lowest 32 bits.
152 return ((uint32_t) x) - 1000000000 * ((uint32_t) div1e9(x));
153 }
154
155 #else // defined(RYU_32_BIT_PLATFORM)
156
div5(const uint64_t x)157 static inline uint64_t div5(const uint64_t x) {
158 return x / 5;
159 }
160
div10(const uint64_t x)161 static inline uint64_t div10(const uint64_t x) {
162 return x / 10;
163 }
164
div100(const uint64_t x)165 static inline uint64_t div100(const uint64_t x) {
166 return x / 100;
167 }
168
div1e8(const uint64_t x)169 static inline uint64_t div1e8(const uint64_t x) {
170 return x / 100000000;
171 }
172
div1e9(const uint64_t x)173 static inline uint64_t div1e9(const uint64_t x) {
174 return x / 1000000000;
175 }
176
mod1e9(const uint64_t x)177 static inline uint32_t mod1e9(const uint64_t x) {
178 return (uint32_t) (x - 1000000000 * div1e9(x));
179 }
180
181 #endif // defined(RYU_32_BIT_PLATFORM)
182
pow5Factor(uint64_t value)183 static inline uint32_t pow5Factor(uint64_t value) {
184 uint32_t count = 0;
185 for (;;) {
186 assert(value != 0);
187 const uint64_t q = div5(value);
188 const uint32_t r = ((uint32_t) value) - 5 * ((uint32_t) q);
189 if (r != 0) {
190 break;
191 }
192 value = q;
193 ++count;
194 }
195 return count;
196 }
197
198 // Returns true if value is divisible by 5^p.
multipleOfPowerOf5(const uint64_t value,const uint32_t p)199 static inline bool multipleOfPowerOf5(const uint64_t value, const uint32_t p) {
200 // I tried a case distinction on p, but there was no performance difference.
201 return pow5Factor(value) >= p;
202 }
203
204 // Returns true if value is divisible by 2^p.
multipleOfPowerOf2(const uint64_t value,const uint32_t p)205 static inline bool multipleOfPowerOf2(const uint64_t value, const uint32_t p) {
206 assert(value != 0);
207 assert(p < 64);
208 // __builtin_ctzll doesn't appear to be faster here.
209 return (value & ((1ull << p) - 1)) == 0;
210 }
211
212 // We need a 64x128-bit multiplication and a subsequent 128-bit shift.
213 // Multiplication:
214 // The 64-bit factor is variable and passed in, the 128-bit factor comes
215 // from a lookup table. We know that the 64-bit factor only has 55
216 // significant bits (i.e., the 9 topmost bits are zeros). The 128-bit
217 // factor only has 124 significant bits (i.e., the 4 topmost bits are
218 // zeros).
219 // Shift:
220 // In principle, the multiplication result requires 55 + 124 = 179 bits to
221 // represent. However, we then shift this value to the right by j, which is
222 // at least j >= 115, so the result is guaranteed to fit into 179 - 115 = 64
223 // bits. This means that we only need the topmost 64 significant bits of
224 // the 64x128-bit multiplication.
225 //
226 // There are several ways to do this:
227 // 1. Best case: the compiler exposes a 128-bit type.
228 // We perform two 64x64-bit multiplications, add the higher 64 bits of the
229 // lower result to the higher result, and shift by j - 64 bits.
230 //
231 // We explicitly cast from 64-bit to 128-bit, so the compiler can tell
232 // that these are only 64-bit inputs, and can map these to the best
233 // possible sequence of assembly instructions.
234 // x64 machines happen to have matching assembly instructions for
235 // 64x64-bit multiplications and 128-bit shifts.
236 //
237 // 2. Second best case: the compiler exposes intrinsics for the x64 assembly
238 // instructions mentioned in 1.
239 //
240 // 3. We only have 64x64 bit instructions that return the lower 64 bits of
241 // the result, i.e., we have to use plain C.
242 // Our inputs are less than the full width, so we have three options:
243 // a. Ignore this fact and just implement the intrinsics manually.
244 // b. Split both into 31-bit pieces, which guarantees no internal overflow,
245 // but requires extra work upfront (unless we change the lookup table).
246 // c. Split only the first factor into 31-bit pieces, which also guarantees
247 // no internal overflow, but requires extra work since the intermediate
248 // results are not perfectly aligned.
249 #if defined(HAS_UINT128)
250
251 // Best case: use 128-bit type.
mulShift64(const uint64_t m,const uint64_t * const mul,const int32_t j)252 static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
253 const uint128_t b0 = ((uint128_t) m) * mul[0];
254 const uint128_t b2 = ((uint128_t) m) * mul[1];
255 return (uint64_t) (((b0 >> 64) + b2) >> (j - 64));
256 }
257
mulShiftAll64(const uint64_t m,const uint64_t * const mul,const int32_t j,uint64_t * const vp,uint64_t * const vm,const uint32_t mmShift)258 static inline uint64_t mulShiftAll64(const uint64_t m, const uint64_t* const mul, const int32_t j,
259 uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) {
260 // m <<= 2;
261 // uint128_t b0 = ((uint128_t) m) * mul[0]; // 0
262 // uint128_t b2 = ((uint128_t) m) * mul[1]; // 64
263 //
264 // uint128_t hi = (b0 >> 64) + b2;
265 // uint128_t lo = b0 & 0xffffffffffffffffull;
266 // uint128_t factor = (((uint128_t) mul[1]) << 64) + mul[0];
267 // uint128_t vpLo = lo + (factor << 1);
268 // *vp = (uint64_t) ((hi + (vpLo >> 64)) >> (j - 64));
269 // uint128_t vmLo = lo - (factor << mmShift);
270 // *vm = (uint64_t) ((hi + (vmLo >> 64) - (((uint128_t) 1ull) << 64)) >> (j - 64));
271 // return (uint64_t) (hi >> (j - 64));
272 *vp = mulShift64(4 * m + 2, mul, j);
273 *vm = mulShift64(4 * m - 1 - mmShift, mul, j);
274 return mulShift64(4 * m, mul, j);
275 }
276
277 #elif defined(HAS_64_BIT_INTRINSICS)
278
mulShift64(const uint64_t m,const uint64_t * const mul,const int32_t j)279 static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
280 // m is maximum 55 bits
281 uint64_t high1; // 128
282 const uint64_t low1 = umul128(m, mul[1], &high1); // 64
283 uint64_t high0; // 64
284 umul128(m, mul[0], &high0); // 0
285 const uint64_t sum = high0 + low1;
286 if (sum < high0) {
287 ++high1; // overflow into high1
288 }
289 return shiftright128(sum, high1, j - 64);
290 }
291
mulShiftAll64(const uint64_t m,const uint64_t * const mul,const int32_t j,uint64_t * const vp,uint64_t * const vm,const uint32_t mmShift)292 static inline uint64_t mulShiftAll64(const uint64_t m, const uint64_t* const mul, const int32_t j,
293 uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) {
294 *vp = mulShift64(4 * m + 2, mul, j);
295 *vm = mulShift64(4 * m - 1 - mmShift, mul, j);
296 return mulShift64(4 * m, mul, j);
297 }
298
299 #else // !defined(HAS_UINT128) && !defined(HAS_64_BIT_INTRINSICS)
300
mulShift64(const uint64_t m,const uint64_t * const mul,const int32_t j)301 static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
302 // m is maximum 55 bits
303 uint64_t high1; // 128
304 const uint64_t low1 = umul128(m, mul[1], &high1); // 64
305 uint64_t high0; // 64
306 umul128(m, mul[0], &high0); // 0
307 const uint64_t sum = high0 + low1;
308 if (sum < high0) {
309 ++high1; // overflow into high1
310 }
311 return shiftright128(sum, high1, j - 64);
312 }
313
314 // This is faster if we don't have a 64x64->128-bit multiplication.
mulShiftAll64(uint64_t m,const uint64_t * const mul,const int32_t j,uint64_t * const vp,uint64_t * const vm,const uint32_t mmShift)315 static inline uint64_t mulShiftAll64(uint64_t m, const uint64_t* const mul, const int32_t j,
316 uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) {
317 m <<= 1;
318 // m is maximum 55 bits
319 uint64_t tmp;
320 const uint64_t lo = umul128(m, mul[0], &tmp);
321 uint64_t hi;
322 const uint64_t mid = tmp + umul128(m, mul[1], &hi);
323 hi += mid < tmp; // overflow into hi
324
325 const uint64_t lo2 = lo + mul[0];
326 const uint64_t mid2 = mid + mul[1] + (lo2 < lo);
327 const uint64_t hi2 = hi + (mid2 < mid);
328 *vp = shiftright128(mid2, hi2, (uint32_t) (j - 64 - 1));
329
330 if (mmShift == 1) {
331 const uint64_t lo3 = lo - mul[0];
332 const uint64_t mid3 = mid - mul[1] - (lo3 > lo);
333 const uint64_t hi3 = hi - (mid3 > mid);
334 *vm = shiftright128(mid3, hi3, (uint32_t) (j - 64 - 1));
335 } else {
336 const uint64_t lo3 = lo + lo;
337 const uint64_t mid3 = mid + mid + (lo3 < lo);
338 const uint64_t hi3 = hi + hi + (mid3 < mid);
339 const uint64_t lo4 = lo3 - mul[0];
340 const uint64_t mid4 = mid3 - mul[1] - (lo4 > lo3);
341 const uint64_t hi4 = hi3 - (mid4 > mid3);
342 *vm = shiftright128(mid4, hi4, (uint32_t) (j - 64));
343 }
344
345 return shiftright128(mid, hi, (uint32_t) (j - 64 - 1));
346 }
347
348 #endif // HAS_64_BIT_INTRINSICS
349
350 #endif // RYU_D2S_INTRINSICS_H
351