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