1 //===-- include/flang/Common/uint128.h --------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // Portable 128-bit unsigned integer arithmetic for use in impoverished
10 // C++ implementations lacking __uint128_t.
11 
12 #ifndef FORTRAN_COMMON_UINT128_H_
13 #define FORTRAN_COMMON_UINT128_H_
14 
15 // Define AVOID_NATIVE_UINT128_T to force the use of UnsignedInt128 below
16 // instead of the C++ compiler's native 128-bit unsigned integer type, if
17 // it has one.
18 #ifndef AVOID_NATIVE_UINT128_T
19 #define AVOID_NATIVE_UINT128_T 0
20 #endif
21 
22 #include "leading-zero-bit-count.h"
23 #include <cstdint>
24 #include <type_traits>
25 
26 namespace Fortran::common {
27 
28 template <bool IS_SIGNED = false> class Int128 {
29 public:
Int128()30   constexpr Int128() {}
31   // This means of definition provides some portability for
32   // "size_t" operands.
Int128(unsigned n)33   constexpr Int128(unsigned n) : low_{n} {}
Int128(unsigned long n)34   constexpr Int128(unsigned long n) : low_{n} {}
Int128(unsigned long long n)35   constexpr Int128(unsigned long long n) : low_{n} {}
Int128(int n)36   constexpr Int128(int n)
37       : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
38                                                  n < 0)} {}
Int128(long n)39   constexpr Int128(long n)
40       : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
41                                                  n < 0)} {}
Int128(long long n)42   constexpr Int128(long long n)
43       : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
44                                                  n < 0)} {}
45   constexpr Int128(const Int128 &) = default;
46   constexpr Int128(Int128 &&) = default;
47   constexpr Int128 &operator=(const Int128 &) = default;
48   constexpr Int128 &operator=(Int128 &&) = default;
49 
50   constexpr Int128 operator+() const { return *this; }
51   constexpr Int128 operator~() const { return {~high_, ~low_}; }
52   constexpr Int128 operator-() const { return ~*this + 1; }
53   constexpr bool operator!() const { return !low_ && !high_; }
54   constexpr explicit operator bool() const { return low_ || high_; }
uint64_t()55   constexpr explicit operator std::uint64_t() const { return low_; }
int64_t()56   constexpr explicit operator std::int64_t() const { return low_; }
57   constexpr explicit operator int() const { return static_cast<int>(low_); }
58 
high()59   constexpr std::uint64_t high() const { return high_; }
low()60   constexpr std::uint64_t low() const { return low_; }
61 
62   constexpr Int128 operator++(/*prefix*/) {
63     *this += 1;
64     return *this;
65   }
66   constexpr Int128 operator++(int /*postfix*/) {
67     Int128 result{*this};
68     *this += 1;
69     return result;
70   }
71   constexpr Int128 operator--(/*prefix*/) {
72     *this -= 1;
73     return *this;
74   }
75   constexpr Int128 operator--(int /*postfix*/) {
76     Int128 result{*this};
77     *this -= 1;
78     return result;
79   }
80 
81   constexpr Int128 operator&(Int128 that) const {
82     return {high_ & that.high_, low_ & that.low_};
83   }
84   constexpr Int128 operator|(Int128 that) const {
85     return {high_ | that.high_, low_ | that.low_};
86   }
87   constexpr Int128 operator^(Int128 that) const {
88     return {high_ ^ that.high_, low_ ^ that.low_};
89   }
90 
91   constexpr Int128 operator<<(Int128 that) const {
92     if (that >= 128) {
93       return {};
94     } else if (that == 0) {
95       return *this;
96     } else {
97       std::uint64_t n{that.low_};
98       if (n >= 64) {
99         return {low_ << (n - 64), 0};
100       } else {
101         return {(high_ << n) | (low_ >> (64 - n)), low_ << n};
102       }
103     }
104   }
105   constexpr Int128 operator>>(Int128 that) const {
106     if (that >= 128) {
107       return {};
108     } else if (that == 0) {
109       return *this;
110     } else {
111       std::uint64_t n{that.low_};
112       if (n >= 64) {
113         return {0, high_ >> (n - 64)};
114       } else {
115         return {high_ >> n, (high_ << (64 - n)) | (low_ >> n)};
116       }
117     }
118   }
119 
120   constexpr Int128 operator+(Int128 that) const {
121     std::uint64_t lower{(low_ & ~topBit) + (that.low_ & ~topBit)};
122     bool carry{((lower >> 63) + (low_ >> 63) + (that.low_ >> 63)) > 1};
123     return {high_ + that.high_ + carry, low_ + that.low_};
124   }
125   constexpr Int128 operator-(Int128 that) const { return *this + -that; }
126 
127   constexpr Int128 operator*(Int128 that) const {
128     std::uint64_t mask32{0xffffffff};
129     if (high_ == 0 && that.high_ == 0) {
130       std::uint64_t x0{low_ & mask32}, x1{low_ >> 32};
131       std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32};
132       Int128 x0y0{x0 * y0}, x0y1{x0 * y1};
133       Int128 x1y0{x1 * y0}, x1y1{x1 * y1};
134       return x0y0 + ((x0y1 + x1y0) << 32) + (x1y1 << 64);
135     } else {
136       std::uint64_t x0{low_ & mask32}, x1{low_ >> 32}, x2{high_ & mask32},
137           x3{high_ >> 32};
138       std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32},
139           y2{that.high_ & mask32}, y3{that.high_ >> 32};
140       Int128 x0y0{x0 * y0}, x0y1{x0 * y1}, x0y2{x0 * y2}, x0y3{x0 * y3};
141       Int128 x1y0{x1 * y0}, x1y1{x1 * y1}, x1y2{x1 * y2};
142       Int128 x2y0{x2 * y0}, x2y1{x2 * y1};
143       Int128 x3y0{x3 * y0};
144       return x0y0 + ((x0y1 + x1y0) << 32) + ((x0y2 + x1y1 + x2y0) << 64) +
145           ((x0y3 + x1y2 + x2y1 + x3y0) << 96);
146     }
147   }
148 
149   constexpr Int128 operator/(Int128 that) const {
150     int j{LeadingZeroes()};
151     Int128 bits{*this};
152     bits <<= j;
153     Int128 numerator{};
154     Int128 quotient{};
155     for (; j < 128; ++j) {
156       numerator <<= 1;
157       if (bits.high_ & topBit) {
158         numerator.low_ |= 1;
159       }
160       bits <<= 1;
161       quotient <<= 1;
162       if (numerator >= that) {
163         ++quotient;
164         numerator -= that;
165       }
166     }
167     return quotient;
168   }
169 
170   constexpr Int128 operator%(Int128 that) const {
171     int j{LeadingZeroes()};
172     Int128 bits{*this};
173     bits <<= j;
174     Int128 remainder{};
175     for (; j < 128; ++j) {
176       remainder <<= 1;
177       if (bits.high_ & topBit) {
178         remainder.low_ |= 1;
179       }
180       bits <<= 1;
181       if (remainder >= that) {
182         remainder -= that;
183       }
184     }
185     return remainder;
186   }
187 
188   constexpr bool operator<(Int128 that) const {
189     if (IS_SIGNED && (high_ ^ that.high_) & topBit) {
190       return (high_ & topBit) != 0;
191     }
192     return high_ < that.high_ || (high_ == that.high_ && low_ < that.low_);
193   }
194   constexpr bool operator<=(Int128 that) const { return !(*this > that); }
195   constexpr bool operator==(Int128 that) const {
196     return low_ == that.low_ && high_ == that.high_;
197   }
198   constexpr bool operator!=(Int128 that) const { return !(*this == that); }
199   constexpr bool operator>=(Int128 that) const { return that <= *this; }
200   constexpr bool operator>(Int128 that) const { return that < *this; }
201 
202   constexpr Int128 &operator&=(const Int128 &that) {
203     *this = *this & that;
204     return *this;
205   }
206   constexpr Int128 &operator|=(const Int128 &that) {
207     *this = *this | that;
208     return *this;
209   }
210   constexpr Int128 &operator^=(const Int128 &that) {
211     *this = *this ^ that;
212     return *this;
213   }
214   constexpr Int128 &operator<<=(const Int128 &that) {
215     *this = *this << that;
216     return *this;
217   }
218   constexpr Int128 &operator>>=(const Int128 &that) {
219     *this = *this >> that;
220     return *this;
221   }
222   constexpr Int128 &operator+=(const Int128 &that) {
223     *this = *this + that;
224     return *this;
225   }
226   constexpr Int128 &operator-=(const Int128 &that) {
227     *this = *this - that;
228     return *this;
229   }
230   constexpr Int128 &operator*=(const Int128 &that) {
231     *this = *this * that;
232     return *this;
233   }
234   constexpr Int128 &operator/=(const Int128 &that) {
235     *this = *this / that;
236     return *this;
237   }
238   constexpr Int128 &operator%=(const Int128 &that) {
239     *this = *this % that;
240     return *this;
241   }
242 
243 private:
Int128(std::uint64_t hi,std::uint64_t lo)244   constexpr Int128(std::uint64_t hi, std::uint64_t lo) : low_{lo}, high_{hi} {}
LeadingZeroes()245   constexpr int LeadingZeroes() const {
246     if (high_ == 0) {
247       return 64 + LeadingZeroBitCount(low_);
248     } else {
249       return LeadingZeroBitCount(high_);
250     }
251   }
252   static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
253   std::uint64_t low_{0}, high_{0};
254 };
255 
256 using UnsignedInt128 = Int128<false>;
257 using SignedInt128 = Int128<true>;
258 
259 #if !AVOID_NATIVE_UINT128_t && (defined __GNUC__ || defined __clang__) && \
260     defined __SIZEOF_INT128__
261 using uint128_t = __uint128_t;
262 using int128_t = __int128_t;
263 #else
264 using uint128_t = UnsignedInt128;
265 using int128_t = SignedInt128;
266 #endif
267 
268 template <int BITS> struct HostUnsignedIntTypeHelper {
269   using type = std::conditional_t<(BITS <= 8), std::uint8_t,
270       std::conditional_t<(BITS <= 16), std::uint16_t,
271           std::conditional_t<(BITS <= 32), std::uint32_t,
272               std::conditional_t<(BITS <= 64), std::uint64_t, uint128_t>>>>;
273 };
274 template <int BITS> struct HostSignedIntTypeHelper {
275   using type = std::conditional_t<(BITS <= 8), std::int8_t,
276       std::conditional_t<(BITS <= 16), std::int16_t,
277           std::conditional_t<(BITS <= 32), std::int32_t,
278               std::conditional_t<(BITS <= 64), std::int64_t, int128_t>>>>;
279 };
280 template <int BITS>
281 using HostUnsignedIntType = typename HostUnsignedIntTypeHelper<BITS>::type;
282 template <int BITS>
283 using HostSignedIntType = typename HostSignedIntTypeHelper<BITS>::type;
284 
285 } // namespace Fortran::common
286 #endif
287