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 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 class UnsignedInt128 {
29 public:
30 constexpr UnsignedInt128() {}
31 // This means of definition provides some portability for
32 // "size_t" operands.
33 constexpr UnsignedInt128(unsigned n) : low_{n} {}
34 constexpr UnsignedInt128(unsigned long n) : low_{n} {}
35 constexpr UnsignedInt128(unsigned long long n) : low_{n} {}
36 constexpr UnsignedInt128(int n)
37 : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
38 n < 0)} {}
39 constexpr UnsignedInt128(long n)
40 : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
41 n < 0)} {}
42 constexpr UnsignedInt128(long long n)
43 : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(
44 n < 0)} {}
45 constexpr UnsignedInt128(const UnsignedInt128 &) = default;
46 constexpr UnsignedInt128(UnsignedInt128 &&) = default;
47 constexpr UnsignedInt128 &operator=(const UnsignedInt128 &) = default;
48 constexpr UnsignedInt128 &operator=(UnsignedInt128 &&) = default;
49
50 constexpr UnsignedInt128 operator+() const { return *this; }
51 constexpr UnsignedInt128 operator~() const { return {~high_, ~low_}; }
52 constexpr UnsignedInt128 operator-() const { return ~*this + 1; }
53 constexpr bool operator!() const { return !low_ && !high_; }
54 constexpr explicit operator bool() const { return low_ || high_; }
55 constexpr explicit operator std::uint64_t() const { return low_; }
56 constexpr explicit operator int() const { return static_cast<int>(low_); }
57
58 constexpr std::uint64_t high() const { return high_; }
59 constexpr std::uint64_t low() const { return low_; }
60
61 constexpr UnsignedInt128 operator++(/*prefix*/) {
62 *this += 1;
63 return *this;
64 }
65 constexpr UnsignedInt128 operator++(int /*postfix*/) {
66 UnsignedInt128 result{*this};
67 *this += 1;
68 return result;
69 }
70 constexpr UnsignedInt128 operator--(/*prefix*/) {
71 *this -= 1;
72 return *this;
73 }
74 constexpr UnsignedInt128 operator--(int /*postfix*/) {
75 UnsignedInt128 result{*this};
76 *this -= 1;
77 return result;
78 }
79
80 constexpr UnsignedInt128 operator&(UnsignedInt128 that) const {
81 return {high_ & that.high_, low_ & that.low_};
82 }
83 constexpr UnsignedInt128 operator|(UnsignedInt128 that) const {
84 return {high_ | that.high_, low_ | that.low_};
85 }
86 constexpr UnsignedInt128 operator^(UnsignedInt128 that) const {
87 return {high_ ^ that.high_, low_ ^ that.low_};
88 }
89
90 constexpr UnsignedInt128 operator<<(UnsignedInt128 that) const {
91 if (that >= 128) {
92 return {};
93 } else if (that == 0) {
94 return *this;
95 } else {
96 std::uint64_t n{that.low_};
97 if (n >= 64) {
98 return {low_ << (n - 64), 0};
99 } else {
100 return {(high_ << n) | (low_ >> (64 - n)), low_ << n};
101 }
102 }
103 }
104 constexpr UnsignedInt128 operator>>(UnsignedInt128 that) const {
105 if (that >= 128) {
106 return {};
107 } else if (that == 0) {
108 return *this;
109 } else {
110 std::uint64_t n{that.low_};
111 if (n >= 64) {
112 return {0, high_ >> (n - 64)};
113 } else {
114 return {high_ >> n, (high_ << (64 - n)) | (low_ >> n)};
115 }
116 }
117 }
118
119 constexpr UnsignedInt128 operator+(UnsignedInt128 that) const {
120 std::uint64_t lower{(low_ & ~topBit) + (that.low_ & ~topBit)};
121 bool carry{((lower >> 63) + (low_ >> 63) + (that.low_ >> 63)) > 1};
122 return {high_ + that.high_ + carry, low_ + that.low_};
123 }
124 constexpr UnsignedInt128 operator-(UnsignedInt128 that) const {
125 return *this + -that;
126 }
127
128 constexpr UnsignedInt128 operator*(UnsignedInt128 that) const {
129 std::uint64_t mask32{0xffffffff};
130 if (high_ == 0 && that.high_ == 0) {
131 std::uint64_t x0{low_ & mask32}, x1{low_ >> 32};
132 std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32};
133 UnsignedInt128 x0y0{x0 * y0}, x0y1{x0 * y1};
134 UnsignedInt128 x1y0{x1 * y0}, x1y1{x1 * y1};
135 return x0y0 + ((x0y1 + x1y0) << 32) + (x1y1 << 64);
136 } else {
137 std::uint64_t x0{low_ & mask32}, x1{low_ >> 32}, x2{high_ & mask32},
138 x3{high_ >> 32};
139 std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32},
140 y2{that.high_ & mask32}, y3{that.high_ >> 32};
141 UnsignedInt128 x0y0{x0 * y0}, x0y1{x0 * y1}, x0y2{x0 * y2}, x0y3{x0 * y3};
142 UnsignedInt128 x1y0{x1 * y0}, x1y1{x1 * y1}, x1y2{x1 * y2};
143 UnsignedInt128 x2y0{x2 * y0}, x2y1{x2 * y1};
144 UnsignedInt128 x3y0{x3 * y0};
145 return x0y0 + ((x0y1 + x1y0) << 32) + ((x0y2 + x1y1 + x2y0) << 64) +
146 ((x0y3 + x1y2 + x2y1 + x3y0) << 96);
147 }
148 }
149
150 constexpr UnsignedInt128 operator/(UnsignedInt128 that) const {
151 int j{LeadingZeroes()};
152 UnsignedInt128 bits{*this};
153 bits <<= j;
154 UnsignedInt128 numerator{};
155 UnsignedInt128 quotient{};
156 for (; j < 128; ++j) {
157 numerator <<= 1;
158 if (bits.high_ & topBit) {
159 numerator.low_ |= 1;
160 }
161 bits <<= 1;
162 quotient <<= 1;
163 if (numerator >= that) {
164 ++quotient;
165 numerator -= that;
166 }
167 }
168 return quotient;
169 }
170
171 constexpr UnsignedInt128 operator%(UnsignedInt128 that) const {
172 int j{LeadingZeroes()};
173 UnsignedInt128 bits{*this};
174 bits <<= j;
175 UnsignedInt128 remainder{};
176 for (; j < 128; ++j) {
177 remainder <<= 1;
178 if (bits.high_ & topBit) {
179 remainder.low_ |= 1;
180 }
181 bits <<= 1;
182 if (remainder >= that) {
183 remainder -= that;
184 }
185 }
186 return remainder;
187 }
188
189 constexpr bool operator<(UnsignedInt128 that) const {
190 return high_ < that.high_ || (high_ == that.high_ && low_ < that.low_);
191 }
192 constexpr bool operator<=(UnsignedInt128 that) const {
193 return !(*this > that);
194 }
195 constexpr bool operator==(UnsignedInt128 that) const {
196 return low_ == that.low_ && high_ == that.high_;
197 }
198 constexpr bool operator!=(UnsignedInt128 that) const {
199 return !(*this == that);
200 }
201 constexpr bool operator>=(UnsignedInt128 that) const { return that <= *this; }
202 constexpr bool operator>(UnsignedInt128 that) const { return that < *this; }
203
204 constexpr UnsignedInt128 &operator&=(const UnsignedInt128 &that) {
205 *this = *this & that;
206 return *this;
207 }
208 constexpr UnsignedInt128 &operator|=(const UnsignedInt128 &that) {
209 *this = *this | that;
210 return *this;
211 }
212 constexpr UnsignedInt128 &operator^=(const UnsignedInt128 &that) {
213 *this = *this ^ that;
214 return *this;
215 }
216 constexpr UnsignedInt128 &operator<<=(const UnsignedInt128 &that) {
217 *this = *this << that;
218 return *this;
219 }
220 constexpr UnsignedInt128 &operator>>=(const UnsignedInt128 &that) {
221 *this = *this >> that;
222 return *this;
223 }
224 constexpr UnsignedInt128 &operator+=(const UnsignedInt128 &that) {
225 *this = *this + that;
226 return *this;
227 }
228 constexpr UnsignedInt128 &operator-=(const UnsignedInt128 &that) {
229 *this = *this - that;
230 return *this;
231 }
232 constexpr UnsignedInt128 &operator*=(const UnsignedInt128 &that) {
233 *this = *this * that;
234 return *this;
235 }
236 constexpr UnsignedInt128 &operator/=(const UnsignedInt128 &that) {
237 *this = *this / that;
238 return *this;
239 }
240 constexpr UnsignedInt128 &operator%=(const UnsignedInt128 &that) {
241 *this = *this % that;
242 return *this;
243 }
244
245 private:
246 constexpr UnsignedInt128(std::uint64_t hi, std::uint64_t lo)
247 : low_{lo}, high_{hi} {}
248 constexpr int LeadingZeroes() const {
249 if (high_ == 0) {
250 return 64 + LeadingZeroBitCount(low_);
251 } else {
252 return LeadingZeroBitCount(high_);
253 }
254 }
255 static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
256 std::uint64_t low_{0}, high_{0};
257 };
258
259 #if AVOID_NATIVE_UINT128_T
260 using uint128_t = UnsignedInt128;
261 #elif (defined __GNUC__ || defined __clang__) && defined __SIZEOF_INT128__
262 using uint128_t = __uint128_t;
263 #else
264 using uint128_t = UnsignedInt128;
265 #endif
266
267 template <int BITS> struct HostUnsignedIntTypeHelper {
268 using type = std::conditional_t<(BITS <= 8), std::uint8_t,
269 std::conditional_t<(BITS <= 16), std::uint16_t,
270 std::conditional_t<(BITS <= 32), std::uint32_t,
271 std::conditional_t<(BITS <= 64), std::uint64_t, uint128_t>>>>;
272 };
273 template <int BITS>
274 using HostUnsignedIntType = typename HostUnsignedIntTypeHelper<BITS>::type;
275
276 } // namespace Fortran::common
277 #endif
Fortran::common::HostUnsignedIntTypeHelper
Definition: uint128.h:267
Fortran::common::UnsignedInt128
Definition: uint128.h:28