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