FLANG
uint128.h
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 integer arithmetic for use in impoverished C++
10// implementations lacking __uint128_t & __int128_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 "api-attrs.h"
23#include "leading-zero-bit-count.h"
24#include "numeric-limits.h"
25#include <cstdint>
26#include <type_traits>
27
28namespace Fortran::common {
29
30template <bool IS_SIGNED = false> class Int128 {
31 friend class detail::numeric_limits_impl<Int128>;
32
33public:
34 constexpr Int128() {}
35 // This means of definition provides some portability for
36 // "size_t" operands.
37 constexpr Int128(unsigned n) : low_{n} {}
38 constexpr Int128(unsigned long n) : low_{n} {}
39 constexpr Int128(unsigned long long n) : low_{n} {}
40 constexpr Int128(int n) {
41 low_ = static_cast<std::uint64_t>(n);
42 high_ = -static_cast<std::uint64_t>(n < 0);
43 }
44 constexpr Int128(long n) {
45 low_ = static_cast<std::uint64_t>(n);
46 high_ = -static_cast<std::uint64_t>(n < 0);
47 }
48 constexpr Int128(long long n) {
49 low_ = static_cast<std::uint64_t>(n);
50 high_ = -static_cast<std::uint64_t>(n < 0);
51 }
52 constexpr Int128(const Int128 &) = default;
53 constexpr Int128(Int128 &&) = default;
54 constexpr Int128 &operator=(const Int128 &) = default;
55 constexpr Int128 &operator=(Int128 &&) = default;
56
57 explicit constexpr Int128(const Int128<!IS_SIGNED> &n)
58 : low_{n.low()}, high_{n.high()} {}
59 explicit constexpr Int128(Int128<!IS_SIGNED> &&n)
60 : low_{n.low()}, high_{n.high()} {}
61
62 constexpr Int128 operator+() const { return *this; }
63 constexpr Int128 operator~() const { return {~high_, ~low_}; }
64 constexpr Int128 operator-() const { return ~*this + 1; }
65 constexpr bool operator!() const { return !low_ && !high_; }
66 constexpr explicit operator bool() const { return low_ || high_; }
67 constexpr explicit operator std::uint64_t() const { return low_; }
68 constexpr explicit operator std::int64_t() const { return low_; }
69 constexpr explicit operator int() const { return static_cast<int>(low_); }
70
71 constexpr std::uint64_t high() const { return high_; }
72 constexpr std::uint64_t low() const { return low_; }
73
74 constexpr Int128 operator++(/*prefix*/) {
75 *this += 1;
76 return *this;
77 }
78 constexpr Int128 operator++(int /*postfix*/) {
79 Int128 result{*this};
80 *this += 1;
81 return result;
82 }
83 constexpr Int128 operator--(/*prefix*/) {
84 *this -= 1;
85 return *this;
86 }
87 constexpr Int128 operator--(int /*postfix*/) {
88 Int128 result{*this};
89 *this -= 1;
90 return result;
91 }
92
93 constexpr Int128 operator&(Int128 that) const {
94 return {high_ & that.high_, low_ & that.low_};
95 }
96 constexpr Int128 operator|(Int128 that) const {
97 return {high_ | that.high_, low_ | that.low_};
98 }
99 constexpr Int128 operator^(Int128 that) const {
100 return {high_ ^ that.high_, low_ ^ that.low_};
101 }
102
103 constexpr Int128 operator<<(Int128 that) const {
104 if (that >= 128) {
105 return {};
106 } else if (that == 0) {
107 return *this;
108 } else {
109 std::uint64_t n{that.low_};
110 if (n >= 64) {
111 return {low_ << (n - 64), 0};
112 } else {
113 return {(high_ << n) | (low_ >> (64 - n)), low_ << n};
114 }
115 }
116 }
117 constexpr Int128 operator>>(Int128 that) const {
118 if (that >= 128) {
119 return {};
120 } else if (that == 0) {
121 return *this;
122 } else {
123 std::uint64_t n{that.low_};
124 if (n >= 64) {
125 return {0, high_ >> (n - 64)};
126 } else {
127 return {high_ >> n, (high_ << (64 - n)) | (low_ >> n)};
128 }
129 }
130 }
131
132 constexpr Int128 operator+(Int128 that) const {
133 std::uint64_t lower{(low_ & ~topBit) + (that.low_ & ~topBit)};
134 bool carry{((lower >> 63) + (low_ >> 63) + (that.low_ >> 63)) > 1};
135 return {high_ + that.high_ + carry, low_ + that.low_};
136 }
137 constexpr Int128 operator-(Int128 that) const { return *this + -that; }
138
139 constexpr Int128 operator*(Int128 that) const {
140 std::uint64_t mask32{0xffffffff};
141 if (high_ == 0 && that.high_ == 0) {
142 std::uint64_t x0{low_ & mask32}, x1{low_ >> 32};
143 std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32};
144 Int128 x0y0{x0 * y0}, x0y1{x0 * y1};
145 Int128 x1y0{x1 * y0}, x1y1{x1 * y1};
146 return x0y0 + ((x0y1 + x1y0) << 32) + (x1y1 << 64);
147 } else {
148 std::uint64_t x0{low_ & mask32}, x1{low_ >> 32}, x2{high_ & mask32},
149 x3{high_ >> 32};
150 std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32},
151 y2{that.high_ & mask32}, y3{that.high_ >> 32};
152 Int128 x0y0{x0 * y0}, x0y1{x0 * y1}, x0y2{x0 * y2}, x0y3{x0 * y3};
153 Int128 x1y0{x1 * y0}, x1y1{x1 * y1}, x1y2{x1 * y2};
154 Int128 x2y0{x2 * y0}, x2y1{x2 * y1};
155 Int128 x3y0{x3 * y0};
156 return x0y0 + ((x0y1 + x1y0) << 32) + ((x0y2 + x1y1 + x2y0) << 64) +
157 ((x0y3 + x1y2 + x2y1 + x3y0) << 96);
158 }
159 }
160
161 constexpr Int128 operator/(Int128 that) const {
162 int j{LeadingZeroes()};
163 Int128 bits{*this};
164 bits <<= j;
165 Int128 numerator{};
166 Int128 quotient{};
167 for (; j < 128; ++j) {
168 numerator <<= 1;
169 if (bits.high_ & topBit) {
170 numerator.low_ |= 1;
171 }
172 bits <<= 1;
173 quotient <<= 1;
174 if (numerator >= that) {
175 ++quotient;
176 numerator -= that;
177 }
178 }
179 return quotient;
180 }
181
182 constexpr Int128 operator%(Int128 that) const {
183 int j{LeadingZeroes()};
184 Int128 bits{*this};
185 bits <<= j;
186 Int128 remainder{};
187 for (; j < 128; ++j) {
188 remainder <<= 1;
189 if (bits.high_ & topBit) {
190 remainder.low_ |= 1;
191 }
192 bits <<= 1;
193 if (remainder >= that) {
194 remainder -= that;
195 }
196 }
197 return remainder;
198 }
199
200 constexpr bool operator<(Int128 that) const {
201 if (IS_SIGNED && (high_ ^ that.high_) & topBit) {
202 return (high_ & topBit) != 0;
203 }
204 return high_ < that.high_ || (high_ == that.high_ && low_ < that.low_);
205 }
206 constexpr bool operator<=(Int128 that) const { return !(*this > that); }
207 constexpr bool operator==(Int128 that) const {
208 return low_ == that.low_ && high_ == that.high_;
209 }
210 constexpr bool operator!=(Int128 that) const { return !(*this == that); }
211 constexpr bool operator>=(Int128 that) const { return that <= *this; }
212 constexpr bool operator>(Int128 that) const { return that < *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 constexpr Int128 &operator*=(const Int128 &that) {
243 *this = *this * that;
244 return *this;
245 }
246 constexpr Int128 &operator/=(const Int128 &that) {
247 *this = *this / that;
248 return *this;
249 }
250 constexpr Int128 &operator%=(const Int128 &that) {
251 *this = *this % that;
252 return *this;
253 }
254
255private:
256 constexpr Int128(std::uint64_t hi, std::uint64_t lo) {
257 low_ = lo;
258 high_ = hi;
259 }
260 constexpr int LeadingZeroes() const {
261 if (high_ == 0) {
262 return 64 + LeadingZeroBitCount(low_);
263 } else {
264 return LeadingZeroBitCount(high_);
265 }
266 }
267 RT_VAR_GROUP_BEGIN
268 static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
269 RT_VAR_GROUP_END
270#if FLANG_LITTLE_ENDIAN
271 std::uint64_t low_{0}, high_{0};
272#elif FLANG_BIG_ENDIAN
273 std::uint64_t high_{0}, low_{0};
274#else
275#error host endianness is not known
276#endif
277};
278
279using UnsignedInt128 = Int128<false>;
280using SignedInt128 = Int128<true>;
281
282#if !AVOID_NATIVE_UINT128_T && (defined __GNUC__ || defined __clang__) && \
283 defined __SIZEOF_INT128__
284#define USING_NATIVE_INT128_T 1
285using uint128_t = __uint128_t;
286using int128_t = __int128_t;
287#else
288#undef USING_NATIVE_INT128_T
289using uint128_t = UnsignedInt128;
290using int128_t = SignedInt128;
291#endif
292
293template <int BITS> struct HostUnsignedIntTypeHelper {
294 using type = std::conditional_t<(BITS <= 8), std::uint8_t,
295 std::conditional_t<(BITS <= 16), std::uint16_t,
296 std::conditional_t<(BITS <= 32), std::uint32_t,
297 std::conditional_t<(BITS <= 64), std::uint64_t, uint128_t>>>>;
298};
299template <int BITS> struct HostSignedIntTypeHelper {
300 using type = std::conditional_t<(BITS <= 8), std::int8_t,
301 std::conditional_t<(BITS <= 16), std::int16_t,
302 std::conditional_t<(BITS <= 32), std::int32_t,
303 std::conditional_t<(BITS <= 64), std::int64_t, int128_t>>>>;
304};
305template <int BITS>
306using HostUnsignedIntType = typename HostUnsignedIntTypeHelper<BITS>::type;
307template <int BITS>
308using HostSignedIntType = typename HostSignedIntTypeHelper<BITS>::type;
309
310namespace detail {
311
312template <> class numeric_limits_impl<Fortran::common::UnsignedInt128> {
313public:
314 using T = Fortran::common::UnsignedInt128;
315
316 static constexpr bool is_specialized{true};
317 static constexpr bool is_signed{false};
318 static constexpr bool is_integer{true};
319
320 static constexpr T min() { return T{0, 0}; }
321 static constexpr T max() { return T{UINT64_MAX, UINT64_MAX}; }
322 static constexpr T lowest() { return min(); }
323};
324
325template <> class numeric_limits_impl<Fortran::common::SignedInt128> {
326public:
327 using T = Fortran::common::SignedInt128;
328
329 static constexpr bool is_specialized{true};
330 static constexpr bool is_signed{true};
331 static constexpr bool is_integer{true};
332
333 static constexpr T min() {
334 return T{static_cast<std::uint64_t>(INT64_MIN), 0};
335 }
336 static constexpr T max() {
337 return T{static_cast<std::uint64_t>(INT64_MAX), UINT64_MAX};
338 }
339 static constexpr T lowest() { return min(); }
340};
341
342template <> class make_unsigned_impl<Fortran::common::UnsignedInt128> {
343public:
344 using type = Fortran::common::UnsignedInt128;
345};
346
347template <> class make_unsigned_impl<Fortran::common::SignedInt128> {
348public:
349 using type = Fortran::common::UnsignedInt128;
350};
351
352} // namespace detail
353
354} // namespace Fortran::common
355#endif
Definition uint128.h:30
Definition numeric-limits.h:24
Definition numeric-limits.h:19
Definition bit-population-count.h:20
Definition ParserActions.h:24
Definition bit-population-count.h:20