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