1 //===-- include/flang/Decimal/binary-floating-point.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 #ifndef FORTRAN_DECIMAL_BINARY_FLOATING_POINT_H_ 10 #define FORTRAN_DECIMAL_BINARY_FLOATING_POINT_H_ 11 12 // Access and manipulate the fields of an IEEE-754 binary 13 // floating-point value via a generalized template. 14 15 #include "flang/Common/real.h" 16 #include "flang/Common/uint128.h" 17 #include <cinttypes> 18 #include <climits> 19 #include <cstring> 20 #include <type_traits> 21 22 namespace Fortran::decimal { 23 24 template <int BINARY_PRECISION> 25 class BinaryFloatingPointNumber : public common::RealDetails<BINARY_PRECISION> { 26 public: 27 using Details = common::RealDetails<BINARY_PRECISION>; 28 using Details::bits; 29 using Details::decimalPrecision; 30 using Details::decimalRange; 31 using Details::exponentBias; 32 using Details::exponentBits; 33 using Details::isImplicitMSB; 34 using Details::maxDecimalConversionDigits; 35 using Details::maxExponent; 36 using Details::significandBits; 37 38 using RawType = common::HostUnsignedIntType<bits>; 39 static_assert(CHAR_BIT * sizeof(RawType) >= bits); 40 static constexpr RawType significandMask{(RawType{1} << significandBits) - 1}; 41 BinaryFloatingPointNumber()42 constexpr BinaryFloatingPointNumber() {} // zero 43 constexpr BinaryFloatingPointNumber( 44 const BinaryFloatingPointNumber &that) = default; 45 constexpr BinaryFloatingPointNumber( 46 BinaryFloatingPointNumber &&that) = default; 47 constexpr BinaryFloatingPointNumber &operator=( 48 const BinaryFloatingPointNumber &that) = default; 49 constexpr BinaryFloatingPointNumber &operator=( 50 BinaryFloatingPointNumber &&that) = default; BinaryFloatingPointNumber(RawType raw)51 constexpr explicit BinaryFloatingPointNumber(RawType raw) : raw_{raw} {} 52 raw()53 RawType raw() const { return raw_; } 54 BinaryFloatingPointNumber(A x)55 template <typename A> explicit constexpr BinaryFloatingPointNumber(A x) { 56 static_assert(sizeof raw_ <= sizeof x); 57 std::memcpy(reinterpret_cast<void *>(&raw_), 58 reinterpret_cast<const void *>(&x), sizeof raw_); 59 } 60 BiasedExponent()61 constexpr int BiasedExponent() const { 62 return static_cast<int>( 63 (raw_ >> significandBits) & ((1 << exponentBits) - 1)); 64 } UnbiasedExponent()65 constexpr int UnbiasedExponent() const { 66 int biased{BiasedExponent()}; 67 return biased - exponentBias + (biased == 0); 68 } Significand()69 constexpr RawType Significand() const { return raw_ & significandMask; } Fraction()70 constexpr RawType Fraction() const { 71 RawType sig{Significand()}; 72 if (isImplicitMSB && BiasedExponent() > 0) { 73 sig |= RawType{1} << significandBits; 74 } 75 return sig; 76 } 77 IsZero()78 constexpr bool IsZero() const { 79 return (raw_ & ((RawType{1} << (bits - 1)) - 1)) == 0; 80 } IsNaN()81 constexpr bool IsNaN() const { 82 return BiasedExponent() == maxExponent && Significand() != 0; 83 } IsInfinite()84 constexpr bool IsInfinite() const { 85 return BiasedExponent() == maxExponent && Significand() == 0; 86 } IsMaximalFiniteMagnitude()87 constexpr bool IsMaximalFiniteMagnitude() const { 88 return BiasedExponent() == maxExponent - 1 && 89 Significand() == significandMask; 90 } IsNegative()91 constexpr bool IsNegative() const { return ((raw_ >> (bits - 1)) & 1) != 0; } 92 Negate()93 constexpr void Negate() { raw_ ^= RawType{1} << (bits - 1); } 94 95 // For calculating the nearest neighbors of a floating-point value Previous()96 constexpr void Previous() { 97 RemoveExplicitMSB(); 98 --raw_; 99 InsertExplicitMSB(); 100 } Next()101 constexpr void Next() { 102 RemoveExplicitMSB(); 103 ++raw_; 104 InsertExplicitMSB(); 105 } 106 107 private: RemoveExplicitMSB()108 constexpr void RemoveExplicitMSB() { 109 if constexpr (!isImplicitMSB) { 110 raw_ = (raw_ & (significandMask >> 1)) | ((raw_ & ~significandMask) >> 1); 111 } 112 } InsertExplicitMSB()113 constexpr void InsertExplicitMSB() { 114 if constexpr (!isImplicitMSB) { 115 constexpr RawType mask{significandMask >> 1}; 116 raw_ = (raw_ & mask) | ((raw_ & ~mask) << 1); 117 if (BiasedExponent() > 0) { 118 raw_ |= RawType{1} << (significandBits - 1); 119 } 120 } 121 } 122 123 RawType raw_{0}; 124 }; 125 } // namespace Fortran::decimal 126 #endif 127