//===-- Abstract class for bit manipulation of float numbers. ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/common.h" #include "src/__support/libc_assert.h" // LIBC_ASSERT #include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR #include "src/__support/macros/config.h" #include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_FLOAT128 #include "src/__support/math_extras.h" // mask_trailing_ones #include "src/__support/sign.h" // Sign #include "src/__support/uint128.h" #include <stdint.h> namespace LIBC_NAMESPACE_DECL { namespace fputil { // The supported floating point types. enum class FPType { … }; // The classes hierarchy is as follows: // // ┌───────────────────┐ // │ FPLayout<FPType> │ // └─────────▲─────────┘ // │ // ┌─────────┴─────────┐ // │ FPStorage<FPType> │ // └─────────▲─────────┘ // │ // ┌────────────┴─────────────┐ // │ │ // ┌────────┴─────────┐ ┌──────────────┴──────────────────┐ // │ FPRepSem<FPType> │ │ FPRepSem<FPType::X86_Binary80 │ // └────────▲─────────┘ └──────────────▲──────────────────┘ // │ │ // └────────────┬─────────────┘ // │ // ┌───────┴───────┐ // │ FPRepImpl<T> │ // └───────▲───────┘ // │ // ┌────────┴────────┐ // ┌─────┴─────┐ ┌─────┴─────┐ // │ FPRep<T> │ │ FPBits<T> │ // └───────────┘ └───────────┘ // // - 'FPLayout' defines only a few constants, namely the 'StorageType' and // length of the sign, the exponent, fraction and significand parts. // - 'FPStorage' builds more constants on top of those from 'FPLayout' like // exponent bias and masks. It also holds the bit representation of the // floating point as a 'StorageType' type and defines tools to assemble or // test these parts. // - 'FPRepSem' defines functions to interact semantically with the floating // point representation. The default implementation is the one for 'IEEE754', // a specialization is provided for X86 Extended Precision. // - 'FPRepImpl' derives from 'FPRepSem' and adds functions that are common to // all implementations or build on the ones in 'FPRepSem'. // - 'FPRep' exposes all functions from 'FPRepImpl' and returns 'FPRep' // instances when using Builders (static functions to create values). // - 'FPBits' exposes all the functions from 'FPRepImpl' but operates on the // native C++ floating point type instead of 'FPType'. An additional 'get_val' // function allows getting the C++ floating point type value back. Builders // called from 'FPBits' return 'FPBits' instances. namespace internal { // Defines the layout (sign, exponent, significand) of a floating point type in // memory. It also defines its associated StorageType, i.e., the unsigned // integer type used to manipulate its representation. // Additionally we provide the fractional part length, i.e., the number of bits // after the decimal dot when the number is in normal form. template <FPType> struct FPLayout { … }; template <> struct FPLayout<FPType::IEEE754_Binary16> { … }; template <> struct FPLayout<FPType::IEEE754_Binary32> { … }; template <> struct FPLayout<FPType::IEEE754_Binary64> { … }; template <> struct FPLayout<FPType::IEEE754_Binary128> { … }; template <> struct FPLayout<FPType::X86_Binary80> { … }; // FPStorage derives useful constants from the FPLayout above. template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> { … }; // This layer defines all functions that are specific to how the the floating // point type is encoded. It enables constructions, modification and observation // of values manipulated as 'StorageType'. template <FPType fp_type, typename RetT> struct FPRepSem : public FPStorage<fp_type> { … }; // Specialization for the X86 Extended Precision type. FPRepSem<FPType::X86_Binary80, RetT>; // 'FPRepImpl' is the bottom of the class hierarchy that only deals with // 'FPType'. The operations dealing with specific float semantics are // implemented by 'FPRepSem' above and specialized when needed. // // The 'RetT' type is being propagated up to 'FPRepSem' so that the functions // creating new values (Builders) can return the appropriate type. That is, when // creating a value through 'FPBits' below the builder will return an 'FPBits' // value. // FPBits<float>::zero(); // returns an FPBits<> // // When we don't care about specific C++ floating point type we can use // 'FPRep' and specify the 'FPType' directly. // FPRep<FPType::IEEE754_Binary32:>::zero() // returns an FPRep<> template <FPType fp_type, typename RetT> struct FPRepImpl : public FPRepSem<fp_type, RetT> { … }; // A generic class to manipulate floating point formats. // It derives its functionality to FPRepImpl above. template <FPType fp_type> struct FPRep : public FPRepImpl<fp_type, FPRep<fp_type>> { … }; } // namespace internal // Returns the FPType corresponding to C++ type T on the host. template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() { … } // A generic class to manipulate C++ floating point formats. // It derives its functionality to FPRepImpl above. template <typename T> struct FPBits final : public internal::FPRepImpl<get_fp_type<T>(), FPBits<T>> { … }; } // namespace fputil } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H