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