llvm/libc/src/__support/FPUtil/FPBits.h

//===-- 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