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
18 #include <stdbool.h>
19 #include "ryu/common.h"
20 #include "ryu/d2s_intrinsics.h"
21
22 #if !defined(HAS_64_BIT_INTRINSICS)
23
__umul128(const uint64_t a,const uint64_t b,uint64_t * const productHi)24 uint64_t __umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
25 // The casts here help MSVC to avoid calls to the __allmul library function.
26 const uint32_t aLo = (uint32_t)a;
27 const uint32_t aHi = (uint32_t)(a >> 32);
28 const uint32_t bLo = (uint32_t)b;
29 const uint32_t bHi = (uint32_t)(b >> 32);
30
31 const uint64_t b00 = (uint64_t)aLo * bLo;
32 const uint64_t b01 = (uint64_t)aLo * bHi;
33 const uint64_t b10 = (uint64_t)aHi * bLo;
34 const uint64_t b11 = (uint64_t)aHi * bHi;
35
36 const uint32_t b00Lo = (uint32_t)b00;
37 const uint32_t b00Hi = (uint32_t)(b00 >> 32);
38
39 const uint64_t mid1 = b10 + b00Hi;
40 const uint32_t mid1Lo = (uint32_t)(mid1);
41 const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
42
43 const uint64_t mid2 = b01 + mid1Lo;
44 const uint32_t mid2Lo = (uint32_t)(mid2);
45 const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
46
47 const uint64_t pHi = b11 + mid1Hi + mid2Hi;
48 const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
49
50 *productHi = pHi;
51 return pLo;
52 }
53
54 // 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)55 uint64_t __shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
56 // We don't need to handle the case dist >= 64 here (see above).
57 assert(dist < 64);
58 assert(dist > 0);
59 return (hi << (64 - dist)) | (lo >> dist);
60 }
61
62 #endif
63