forked from OSchip/llvm-project
[flang] Add software uint128_t (debugging incomplete)
Original-commit: flang-compiler/f18@5be270e604 Reviewed-on: https://github.com/flang-compiler/f18/pull/785 Tree-same-pre-rewrite: false
This commit is contained in:
parent
416d9ced52
commit
2348d593ae
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Portable 128-bit unsigned integer arithmetic
|
||||
|
||||
#ifndef FORTRAN_COMMON_UINT128_H_
|
||||
#define FORTRAN_COMMON_UINT128_H_
|
||||
|
||||
#define AVOID_NATIVE_UINT128 1 // for testing purposes
|
||||
|
||||
#include "leading-zero-bit-count.h"
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Fortran::common {
|
||||
|
||||
class UnsignedInt128 {
|
||||
public:
|
||||
constexpr UnsignedInt128() {}
|
||||
constexpr UnsignedInt128(std::uint64_t n) : low_{n} {}
|
||||
constexpr UnsignedInt128(std::int64_t n) : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(n<0)} {}
|
||||
constexpr UnsignedInt128(int n) : low_{static_cast<std::uint64_t>(n)}, high_{-static_cast<std::uint64_t>(n<0)} {}
|
||||
constexpr UnsignedInt128(const UnsignedInt128 &) = default;
|
||||
constexpr UnsignedInt128(UnsignedInt128 &&) = default;
|
||||
constexpr UnsignedInt128 &operator=(const UnsignedInt128 &) = default;
|
||||
constexpr UnsignedInt128 &operator=(UnsignedInt128 &&) = default;
|
||||
|
||||
constexpr UnsignedInt128 operator+() const { return *this; }
|
||||
constexpr UnsignedInt128 operator~() const { return {~high_, ~low_}; }
|
||||
constexpr UnsignedInt128 operator-() const { return ~*this + 1; }
|
||||
constexpr bool operator!() const { return !low_ && !high_; }
|
||||
constexpr explicit operator bool() const { return low_ || high_; }
|
||||
constexpr explicit operator std::uint64_t() const { return low_; }
|
||||
constexpr explicit operator int() const { return static_cast<int>(low_); }
|
||||
|
||||
constexpr std::uint64_t high() const { return high_; }
|
||||
constexpr std::uint64_t low() const { return low_; }
|
||||
|
||||
constexpr UnsignedInt128 operator++(/*prefix*/) {
|
||||
*this += 1;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 operator++(int /*postfix*/) {
|
||||
UnsignedInt128 result{*this};
|
||||
*this += 1;
|
||||
return result;
|
||||
}
|
||||
constexpr UnsignedInt128 operator--(/*prefix*/) {
|
||||
*this -= 1;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 operator--(int /*postfix*/) {
|
||||
UnsignedInt128 result{*this};
|
||||
*this -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 operator&(UnsignedInt128 that) const {
|
||||
return {high_ & that.high_, low_ & that.low_};
|
||||
}
|
||||
constexpr UnsignedInt128 operator|(UnsignedInt128 that) const {
|
||||
return {high_ | that.high_, low_ | that.low_};
|
||||
}
|
||||
constexpr UnsignedInt128 operator^(UnsignedInt128 that) const {
|
||||
return {high_ ^ that.high_, low_ ^ that.low_};
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 operator<<(UnsignedInt128 that) const {
|
||||
if (that >= 128) {
|
||||
return {};
|
||||
} else {
|
||||
std::uint64_t n{that.low_};
|
||||
if (n >= 64) {
|
||||
return {low_ << (n - 64), 0};
|
||||
} else {
|
||||
return {(high_ << n) | (low_ >> (64 - n)), low_ << n};
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr UnsignedInt128 operator>>(UnsignedInt128 that) const {
|
||||
if (that >= 128) {
|
||||
return {};
|
||||
} else {
|
||||
std::uint64_t n{that.low_};
|
||||
if (n >= 64) {
|
||||
return {0, high_ >> (n - 64)};
|
||||
} else {
|
||||
return {high_ >> n, (high_ << (64 - n)) | (low_ >> n)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 operator+(UnsignedInt128 that) const {
|
||||
std::uint64_t lower{(low_ & ~topBit) + (that.low_ & ~topBit)};
|
||||
bool carry{((lower >> 63) + (low_ >> 63) + (that.low_ >> 63)) > 1};
|
||||
return {high_ + that.high_ + carry, low_ + that.low_};
|
||||
}
|
||||
constexpr UnsignedInt128 operator-(UnsignedInt128 that) const {
|
||||
return *this + -that;
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 operator*(UnsignedInt128 that) const {
|
||||
std::uint64_t mask32{0xffffffff};
|
||||
if (high_ == 0 && that.high_ == 0) {
|
||||
std::uint64_t x0{low_ & mask32}, x1{low_ >> 32};
|
||||
std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32};
|
||||
UnsignedInt128 x0y0{x0 * y0}, x0y1{x0 * y1};
|
||||
UnsignedInt128 x1y0{x1 * y0}, x1y1{x1 * y1};
|
||||
return x0y0 + ((x0y1 + x1y0) << 32) + (x1y1 << 64);
|
||||
} else {
|
||||
std::uint64_t x0{low_ & mask32}, x1{low_ >> 32}, x2{high_ & mask32}, x3{high_ >> 32};
|
||||
std::uint64_t y0{that.low_ & mask32}, y1{that.low_ >> 32}, y2{that.high_ & mask32}, y3{that.high_ >> 32};
|
||||
UnsignedInt128 x0y0{x0 * y0}, x0y1{x0 * y1}, x0y2{x0 * y2}, x0y3{x0 * y3};
|
||||
UnsignedInt128 x1y0{x1 * y0}, x1y1{x1 * y1}, x1y2{x1 * y2};
|
||||
UnsignedInt128 x2y0{x2 * y0}, x2y1{x2 * y1};
|
||||
UnsignedInt128 x3y0{x3 * y0};
|
||||
return x0y0 + ((x0y1 + x1y0) << 32) + ((x0y2 + x1y1 + x2y0) << 64) + ((x0y3 + x1y2 + x2y1 + x3y0) << 96);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 operator/(UnsignedInt128 that) const {
|
||||
int j{high_ == 0 ? 64 + LeadingZeroBitCount(low_) : LeadingZeroBitCount(high_)};
|
||||
UnsignedInt128 bits{*this};
|
||||
bits <<= j;
|
||||
UnsignedInt128 numerator{};
|
||||
UnsignedInt128 quotient{};
|
||||
for (; j < 128; ++j) {
|
||||
numerator <<= 1;
|
||||
if (bits.high_ & topBit) {
|
||||
numerator.low_ |= 1;
|
||||
}
|
||||
bits <<= 1;
|
||||
quotient <<= 1;
|
||||
if (numerator >= that) {
|
||||
++quotient;
|
||||
numerator -= that;
|
||||
}
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 operator%(UnsignedInt128 that) const {
|
||||
int j{high_ == 0 ? 64 + LeadingZeroBitCount(low_) : LeadingZeroBitCount(high_)};
|
||||
UnsignedInt128 bits{*this};
|
||||
bits <<= j;
|
||||
UnsignedInt128 remainder{};
|
||||
for (; j < 128; ++j) {
|
||||
remainder <<= 1;
|
||||
if (bits.high_ & topBit) {
|
||||
remainder.low_ |= 1;
|
||||
}
|
||||
bits <<= 1;
|
||||
if (remainder >= that) {
|
||||
remainder -= that;
|
||||
}
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
constexpr bool operator<(UnsignedInt128 that) const {
|
||||
return high_ < that.high_ || (high_ == that.high_ && low_ < that.low_);
|
||||
}
|
||||
constexpr bool operator<=(UnsignedInt128 that) const {
|
||||
return !(*this > that);
|
||||
}
|
||||
constexpr bool operator==(UnsignedInt128 that) const {
|
||||
return low_ == that.low_ && high_ == that.high_;
|
||||
}
|
||||
constexpr bool operator!=(UnsignedInt128 that) const {
|
||||
return !(*this == that);
|
||||
}
|
||||
constexpr bool operator>=(UnsignedInt128 that) const {
|
||||
return that <= *this;
|
||||
}
|
||||
constexpr bool operator>(UnsignedInt128 that) const {
|
||||
return that < *this;
|
||||
}
|
||||
|
||||
constexpr UnsignedInt128 &operator&=(const UnsignedInt128 &that) {
|
||||
*this = *this & that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator|=(const UnsignedInt128 &that) {
|
||||
*this = *this | that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator^=(const UnsignedInt128 &that) {
|
||||
*this = *this ^ that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator<<=(const UnsignedInt128 &that) {
|
||||
*this = *this << that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator>>=(const UnsignedInt128 &that) {
|
||||
*this = *this >> that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator+=(const UnsignedInt128 &that) {
|
||||
*this = *this + that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator-=(const UnsignedInt128 &that) {
|
||||
*this = *this - that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator*=(const UnsignedInt128 &that) {
|
||||
*this = *this * that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator/=(const UnsignedInt128 &that) {
|
||||
*this = *this / that;
|
||||
return *this;
|
||||
}
|
||||
constexpr UnsignedInt128 &operator%=(const UnsignedInt128 &that) {
|
||||
*this = *this % that;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr UnsignedInt128(std::uint64_t hi, std::uint64_t lo) : low_{lo}, high_{hi} {}
|
||||
static constexpr std::uint64_t topBit{std::uint64_t{1} << 63};
|
||||
std::uint64_t low_{0}, high_{0};
|
||||
};
|
||||
|
||||
#if (defined __GNUC__ || defined __clang__) && defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128
|
||||
using uint128_t = __uint128_t;
|
||||
#else
|
||||
using uint128_t = UnsignedInt128;
|
||||
#endif
|
||||
|
||||
template<int BITS> struct HostUnsignedIntTypeHelper {
|
||||
using type = std::conditional_t<(BITS <= 8), std::uint8_t,
|
||||
std::conditional_t<(BITS <= 16), std::uint16_t,
|
||||
std::conditional_t<(BITS <= 32), std::uint32_t,
|
||||
std::conditional_t<(BITS <= 64), std::uint64_t, uint128_t>>>>;
|
||||
};
|
||||
template<int BITS>
|
||||
using HostUnsignedIntType = typename HostUnsignedIntTypeHelper<BITS>::type;
|
||||
|
||||
}
|
||||
#endif
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "bit-population-count.h"
|
||||
#include "leading-zero-bit-count.h"
|
||||
#include "uint128.h"
|
||||
#include <cinttypes>
|
||||
#include <type_traits>
|
||||
|
||||
|
@ -35,7 +36,7 @@ private:
|
|||
static_assert(std::is_unsigned_v<type>);
|
||||
static const int bits{static_cast<int>(8 * sizeof(type))};
|
||||
static_assert(bits <= 64);
|
||||
using Big = std::conditional_t<(bits <= 32), std::uint64_t, __uint128_t>;
|
||||
using Big = std::conditional_t<(bits <= 32), std::uint64_t, uint128_t>;
|
||||
|
||||
public:
|
||||
static constexpr FixedPointReciprocal For(type n) {
|
||||
|
@ -50,7 +51,7 @@ public:
|
|||
}
|
||||
|
||||
constexpr type Divide(type n) const {
|
||||
return (static_cast<Big>(reciprocal_) * n) >> shift_;
|
||||
return static_cast<type>((static_cast<Big>(reciprocal_) * n) >> shift_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -65,12 +66,12 @@ static_assert(FixedPointReciprocal<std::uint32_t>::For(5).Divide(2000000000u) ==
|
|||
static_assert(FixedPointReciprocal<std::uint64_t>::For(10).Divide(
|
||||
10000000000000000u) == 1000000000000000u);
|
||||
|
||||
template<typename UINT, UINT DENOM>
|
||||
template<typename UINT, std::uint64_t DENOM>
|
||||
inline constexpr UINT DivideUnsignedBy(UINT n) {
|
||||
if constexpr (!std::is_same_v<UINT, __uint128_t>) {
|
||||
if constexpr (!std::is_same_v<UINT, uint128_t>) {
|
||||
return FixedPointReciprocal<UINT>::For(DENOM).Divide(n);
|
||||
} else {
|
||||
return n / DENOM;
|
||||
return n / static_cast<UINT>(DENOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "decimal.h"
|
||||
#include "../common/bit-population-count.h"
|
||||
#include "../common/leading-zero-bit-count.h"
|
||||
#include "../common/uint128.h"
|
||||
#include "../common/unsigned-const-division.h"
|
||||
#include <cinttypes>
|
||||
#include <limits>
|
||||
|
@ -54,7 +55,7 @@ private:
|
|||
static constexpr std::uint64_t uint64Radix{TenToThe(log10Radix)};
|
||||
static constexpr int minDigitBits{
|
||||
64 - common::LeadingZeroBitCount(uint64Radix)};
|
||||
using Digit = HostUnsignedIntType<minDigitBits>;
|
||||
using Digit = common::HostUnsignedIntType<minDigitBits>;
|
||||
static constexpr Digit radix{uint64Radix};
|
||||
static_assert(radix < std::numeric_limits<Digit>::max() / 1000,
|
||||
"radix is somehow too big");
|
||||
|
@ -146,11 +147,11 @@ private:
|
|||
// Returns any remainder.
|
||||
template<typename UINT> UINT SetTo(UINT n) {
|
||||
static_assert(
|
||||
std::is_same_v<UINT, __uint128_t> || std::is_unsigned_v<UINT>);
|
||||
std::is_same_v<UINT, common::uint128_t> || std::is_unsigned_v<UINT>);
|
||||
SetToZero();
|
||||
while (n != 0) {
|
||||
auto q{common::DivideUnsignedBy<UINT, 10>(n)};
|
||||
if (n != 10 * q) {
|
||||
if (n != q * 10) {
|
||||
break;
|
||||
}
|
||||
++exponent_;
|
||||
|
@ -164,7 +165,7 @@ private:
|
|||
} else {
|
||||
while (n != 0 && digits_ < digitLimit_) {
|
||||
auto q{common::DivideUnsignedBy<UINT, radix>(n)};
|
||||
digit_[digits_++] = n - radix * q;
|
||||
digit_[digits_++] = static_cast<Digit>(n - q * radix);
|
||||
n = q;
|
||||
}
|
||||
return n;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
// Access and manipulate the fields of an IEEE-754 binary
|
||||
// floating-point value via a generalized template.
|
||||
|
||||
#include "../common/uint128.h"
|
||||
#include <cinttypes>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
@ -25,15 +26,6 @@
|
|||
|
||||
namespace Fortran::decimal {
|
||||
|
||||
template<int BITS> struct HostUnsignedIntTypeHelper {
|
||||
using type = std::conditional_t<(BITS <= 8), std::uint8_t,
|
||||
std::conditional_t<(BITS <= 16), std::uint16_t,
|
||||
std::conditional_t<(BITS <= 32), std::uint32_t,
|
||||
std::conditional_t<(BITS <= 64), std::uint64_t, __uint128_t>>>>;
|
||||
};
|
||||
template<int BITS>
|
||||
using HostUnsignedIntType = typename HostUnsignedIntTypeHelper<BITS>::type;
|
||||
|
||||
static constexpr int BitsForPrecision(int prec) {
|
||||
switch (prec) {
|
||||
case 8: return 16;
|
||||
|
@ -52,7 +44,7 @@ static constexpr std::int64_t ScaledLogBaseTenOfTwo{301029995664};
|
|||
template<int PRECISION> struct BinaryFloatingPointNumber {
|
||||
static constexpr int precision{PRECISION};
|
||||
static constexpr int bits{BitsForPrecision(precision)};
|
||||
using RawType = HostUnsignedIntType<bits>;
|
||||
using RawType = common::HostUnsignedIntType<bits>;
|
||||
static_assert(CHAR_BIT * sizeof(RawType) >= bits);
|
||||
static constexpr bool implicitMSB{precision != 64 /*x87*/};
|
||||
static constexpr int significandBits{precision - implicitMSB};
|
||||
|
@ -107,7 +99,7 @@ template<int PRECISION> struct BinaryFloatingPointNumber {
|
|||
return BiasedExponent() == maxExponent - 1 &&
|
||||
Significand() == significandMask;
|
||||
}
|
||||
constexpr bool IsNegative() const { return (raw >> (bits - 1)) & 1; }
|
||||
constexpr bool IsNegative() const { return ((raw >> (bits - 1)) & 1) != 0; }
|
||||
|
||||
constexpr void Negate() { raw ^= RawType{1} << (bits - 1); }
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ bool BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ParseNumber(
|
|||
template<int PREC> class IntermediateFloat {
|
||||
public:
|
||||
static constexpr int precision{PREC};
|
||||
using IntType = HostUnsignedIntType<precision>;
|
||||
using IntType = common::HostUnsignedIntType<precision>;
|
||||
static constexpr IntType topBit{IntType{1} << (precision - 1)};
|
||||
static constexpr IntType mask{topBit + (topBit - 1)};
|
||||
|
||||
|
@ -227,7 +227,7 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
|
|||
// The value is nonzero; normalize it.
|
||||
while (fraction < topBit && expo > 1) {
|
||||
--expo;
|
||||
fraction = 2 * fraction + (guard >> (guardBits - 2));
|
||||
fraction = fraction * 2 + (guard >> (guardBits - 2));
|
||||
guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
|
||||
}
|
||||
// Apply rounding
|
||||
|
|
Loading…
Reference in New Issue