Path: blob/main/contrib/llvm-project/libc/src/__support/FPUtil/FPBits.h
213799 views
//===-- Abstract class for bit manipulation of float numbers. ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78// -----------------------------------------------------------------------------9// **** WARNING ****10// This file is shared with libc++. You should also be careful when adding11// dependencies to this file, since it needs to build for all libc++ targets.12// -----------------------------------------------------------------------------1314#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H15#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H1617#include "src/__support/CPP/bit.h"18#include "src/__support/CPP/type_traits.h"19#include "src/__support/common.h"20#include "src/__support/libc_assert.h" // LIBC_ASSERT21#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR22#include "src/__support/macros/config.h"23#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_FLOAT12824#include "src/__support/math_extras.h" // mask_trailing_ones25#include "src/__support/sign.h" // Sign26#include "src/__support/uint128.h"2728#include <stdint.h>2930namespace LIBC_NAMESPACE_DECL {31namespace fputil {3233// The supported floating point types.34enum class FPType {35IEEE754_Binary16,36IEEE754_Binary32,37IEEE754_Binary64,38IEEE754_Binary128,39X86_Binary80,40BFloat1641};4243// The classes hierarchy is as follows:44//45// ┌───────────────────┐46// │ FPLayout<FPType> │47// └─────────▲─────────┘48// │49// ┌─────────┴─────────┐50// │ FPStorage<FPType> │51// └─────────▲─────────┘52// │53// ┌────────────┴─────────────┐54// │ │55// ┌────────┴─────────┐ ┌──────────────┴──────────────────┐56// │ FPRepSem<FPType> │ │ FPRepSem<FPType::X86_Binary80 │57// └────────▲─────────┘ └──────────────▲──────────────────┘58// │ │59// └────────────┬─────────────┘60// │61// ┌───────┴───────┐62// │ FPRepImpl<T> │63// └───────▲───────┘64// │65// ┌────────┴────────┐66// ┌─────┴─────┐ ┌─────┴─────┐67// │ FPRep<T> │ │ FPBits<T> │68// └───────────┘ └───────────┘69//70// - 'FPLayout' defines only a few constants, namely the 'StorageType' and71// length of the sign, the exponent, fraction and significand parts.72// - 'FPStorage' builds more constants on top of those from 'FPLayout' like73// exponent bias and masks. It also holds the bit representation of the74// floating point as a 'StorageType' type and defines tools to assemble or75// test these parts.76// - 'FPRepSem' defines functions to interact semantically with the floating77// point representation. The default implementation is the one for 'IEEE754',78// a specialization is provided for X86 Extended Precision.79// - 'FPRepImpl' derives from 'FPRepSem' and adds functions that are common to80// all implementations or build on the ones in 'FPRepSem'.81// - 'FPRep' exposes all functions from 'FPRepImpl' and returns 'FPRep'82// instances when using Builders (static functions to create values).83// - 'FPBits' exposes all the functions from 'FPRepImpl' but operates on the84// native C++ floating point type instead of 'FPType'. An additional 'get_val'85// function allows getting the C++ floating point type value back. Builders86// called from 'FPBits' return 'FPBits' instances.8788namespace internal {8990// Defines the layout (sign, exponent, significand) of a floating point type in91// memory. It also defines its associated StorageType, i.e., the unsigned92// integer type used to manipulate its representation.93// Additionally we provide the fractional part length, i.e., the number of bits94// after the decimal dot when the number is in normal form.95template <FPType> struct FPLayout {};9697template <> struct FPLayout<FPType::IEEE754_Binary16> {98using StorageType = uint16_t;99LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;100LIBC_INLINE_VAR static constexpr int EXP_LEN = 5;101LIBC_INLINE_VAR static constexpr int SIG_LEN = 10;102LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN;103};104105template <> struct FPLayout<FPType::IEEE754_Binary32> {106using StorageType = uint32_t;107LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;108LIBC_INLINE_VAR static constexpr int EXP_LEN = 8;109LIBC_INLINE_VAR static constexpr int SIG_LEN = 23;110LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN;111};112113template <> struct FPLayout<FPType::IEEE754_Binary64> {114using StorageType = uint64_t;115LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;116LIBC_INLINE_VAR static constexpr int EXP_LEN = 11;117LIBC_INLINE_VAR static constexpr int SIG_LEN = 52;118LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN;119};120121template <> struct FPLayout<FPType::IEEE754_Binary128> {122using StorageType = UInt128;123LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;124LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;125LIBC_INLINE_VAR static constexpr int SIG_LEN = 112;126LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN;127};128129template <> struct FPLayout<FPType::X86_Binary80> {130#if __SIZEOF_LONG_DOUBLE__ == 12131using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>;132#else133using StorageType = UInt128;134#endif135LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;136LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;137LIBC_INLINE_VAR static constexpr int SIG_LEN = 64;138LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN - 1;139};140141template <> struct FPLayout<FPType::BFloat16> {142using StorageType = uint16_t;143LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;144LIBC_INLINE_VAR static constexpr int EXP_LEN = 8;145LIBC_INLINE_VAR static constexpr int SIG_LEN = 7;146LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN;147};148149// FPStorage derives useful constants from the FPLayout above.150template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {151using UP = FPLayout<fp_type>;152153using UP::EXP_LEN; // The number of bits for the *exponent* part154using UP::SIG_LEN; // The number of bits for the *significand* part155using UP::SIGN_LEN; // The number of bits for the *sign* part156// For convenience, the sum of `SIG_LEN`, `EXP_LEN`, and `SIGN_LEN`.157LIBC_INLINE_VAR static constexpr int TOTAL_LEN = SIGN_LEN + EXP_LEN + SIG_LEN;158159// The number of bits after the decimal dot when the number is in normal form.160using UP::FRACTION_LEN;161162// An unsigned integer that is wide enough to contain all of the floating163// point bits.164using StorageType = typename UP::StorageType;165166// The number of bits in StorageType.167LIBC_INLINE_VAR static constexpr int STORAGE_LEN =168sizeof(StorageType) * CHAR_BIT;169static_assert(STORAGE_LEN >= TOTAL_LEN);170171// The exponent bias. Always positive.172LIBC_INLINE_VAR static constexpr int32_t EXP_BIAS =173(1U << (EXP_LEN - 1U)) - 1U;174static_assert(EXP_BIAS > 0);175176// The bit pattern that keeps only the *significand* part.177LIBC_INLINE_VAR static constexpr StorageType SIG_MASK =178mask_trailing_ones<StorageType, SIG_LEN>();179// The bit pattern that keeps only the *exponent* part.180LIBC_INLINE_VAR static constexpr StorageType EXP_MASK =181mask_trailing_ones<StorageType, EXP_LEN>() << SIG_LEN;182// The bit pattern that keeps only the *sign* part.183LIBC_INLINE_VAR static constexpr StorageType SIGN_MASK =184mask_trailing_ones<StorageType, SIGN_LEN>() << (EXP_LEN + SIG_LEN);185// The bit pattern that keeps only the *exponent + significand* part.186LIBC_INLINE_VAR static constexpr StorageType EXP_SIG_MASK =187mask_trailing_ones<StorageType, EXP_LEN + SIG_LEN>();188// The bit pattern that keeps only the *sign + exponent + significand* part.189LIBC_INLINE_VAR static constexpr StorageType FP_MASK =190mask_trailing_ones<StorageType, TOTAL_LEN>();191// The bit pattern that keeps only the *fraction* part.192// i.e., the *significand* without the leading one.193LIBC_INLINE_VAR static constexpr StorageType FRACTION_MASK =194mask_trailing_ones<StorageType, FRACTION_LEN>();195196static_assert((SIG_MASK & EXP_MASK & SIGN_MASK) == 0, "masks disjoint");197static_assert((SIG_MASK | EXP_MASK | SIGN_MASK) == FP_MASK, "masks cover");198199protected:200// Merge bits from 'a' and 'b' values according to 'mask'.201// Use 'a' bits when corresponding 'mask' bits are zeroes and 'b' bits when202// corresponding bits are ones.203LIBC_INLINE static constexpr StorageType merge(StorageType a, StorageType b,204StorageType mask) {205// https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge206return a ^ ((a ^ b) & mask);207}208209// A stongly typed integer that prevents mixing and matching integers with210// different semantics.211template <typename T> struct TypedInt {212using value_type = T;213LIBC_INLINE constexpr explicit TypedInt(T value) : value(value) {}214LIBC_INLINE constexpr TypedInt(const TypedInt &value) = default;215LIBC_INLINE constexpr TypedInt &operator=(const TypedInt &value) = default;216217LIBC_INLINE constexpr explicit operator T() const { return value; }218219LIBC_INLINE constexpr StorageType to_storage_type() const {220return StorageType(value);221}222223LIBC_INLINE friend constexpr bool operator==(TypedInt a, TypedInt b) {224return a.value == b.value;225}226LIBC_INLINE friend constexpr bool operator!=(TypedInt a, TypedInt b) {227return a.value != b.value;228}229230protected:231T value;232};233234// An opaque type to store a floating point exponent.235// We define special values but it is valid to create arbitrary values as long236// as they are in the range [min, max].237struct Exponent : public TypedInt<int32_t> {238using UP = TypedInt<int32_t>;239using UP::UP;240LIBC_INLINE static constexpr auto subnormal() {241return Exponent(-EXP_BIAS);242}243LIBC_INLINE static constexpr auto min() { return Exponent(1 - EXP_BIAS); }244LIBC_INLINE static constexpr auto zero() { return Exponent(0); }245LIBC_INLINE static constexpr auto max() { return Exponent(EXP_BIAS); }246LIBC_INLINE static constexpr auto inf() { return Exponent(EXP_BIAS + 1); }247};248249// An opaque type to store a floating point biased exponent.250// We define special values but it is valid to create arbitrary values as long251// as they are in the range [zero, bits_all_ones].252// Values greater than bits_all_ones are truncated.253struct BiasedExponent : public TypedInt<uint32_t> {254using UP = TypedInt<uint32_t>;255using UP::UP;256257LIBC_INLINE constexpr BiasedExponent(Exponent exp)258: UP(static_cast<uint32_t>(static_cast<int32_t>(exp) + EXP_BIAS)) {}259260// Cast operator to get convert from BiasedExponent to Exponent.261LIBC_INLINE constexpr operator Exponent() const {262return Exponent(static_cast<int32_t>(UP::value - EXP_BIAS));263}264265LIBC_INLINE constexpr BiasedExponent &operator++() {266LIBC_ASSERT(*this != BiasedExponent(Exponent::inf()));267++UP::value;268return *this;269}270271LIBC_INLINE constexpr BiasedExponent &operator--() {272LIBC_ASSERT(*this != BiasedExponent(Exponent::subnormal()));273--UP::value;274return *this;275}276};277278// An opaque type to store a floating point significand.279// We define special values but it is valid to create arbitrary values as long280// as they are in the range [zero, bits_all_ones].281// Note that the semantics of the Significand are implementation dependent.282// Values greater than bits_all_ones are truncated.283struct Significand : public TypedInt<StorageType> {284using UP = TypedInt<StorageType>;285using UP::UP;286287LIBC_INLINE friend constexpr Significand operator|(const Significand a,288const Significand b) {289return Significand(290StorageType(a.to_storage_type() | b.to_storage_type()));291}292LIBC_INLINE friend constexpr Significand operator^(const Significand a,293const Significand b) {294return Significand(295StorageType(a.to_storage_type() ^ b.to_storage_type()));296}297LIBC_INLINE friend constexpr Significand operator>>(const Significand a,298int shift) {299return Significand(StorageType(a.to_storage_type() >> shift));300}301302LIBC_INLINE static constexpr auto zero() {303return Significand(StorageType(0));304}305LIBC_INLINE static constexpr auto lsb() {306return Significand(StorageType(1));307}308LIBC_INLINE static constexpr auto msb() {309return Significand(StorageType(1) << (SIG_LEN - 1));310}311LIBC_INLINE static constexpr auto bits_all_ones() {312return Significand(SIG_MASK);313}314};315316LIBC_INLINE static constexpr StorageType encode(BiasedExponent exp) {317return (exp.to_storage_type() << SIG_LEN) & EXP_MASK;318}319320LIBC_INLINE static constexpr StorageType encode(Significand value) {321return value.to_storage_type() & SIG_MASK;322}323324LIBC_INLINE static constexpr StorageType encode(BiasedExponent exp,325Significand sig) {326return encode(exp) | encode(sig);327}328329LIBC_INLINE static constexpr StorageType encode(Sign sign, BiasedExponent exp,330Significand sig) {331if (sign.is_neg())332return SIGN_MASK | encode(exp, sig);333return encode(exp, sig);334}335336// The floating point number representation as an unsigned integer.337StorageType bits{};338339LIBC_INLINE constexpr FPStorage() : bits(0) {}340LIBC_INLINE constexpr FPStorage(StorageType value) : bits(value) {}341342// Observers343LIBC_INLINE constexpr StorageType exp_bits() const { return bits & EXP_MASK; }344LIBC_INLINE constexpr StorageType sig_bits() const { return bits & SIG_MASK; }345LIBC_INLINE constexpr StorageType exp_sig_bits() const {346return bits & EXP_SIG_MASK;347}348349// Parts350LIBC_INLINE constexpr BiasedExponent biased_exponent() const {351return BiasedExponent(static_cast<uint32_t>(exp_bits() >> SIG_LEN));352}353LIBC_INLINE constexpr void set_biased_exponent(BiasedExponent biased) {354bits = merge(bits, encode(biased), EXP_MASK);355}356357public:358LIBC_INLINE constexpr Sign sign() const {359return (bits & SIGN_MASK) ? Sign::NEG : Sign::POS;360}361LIBC_INLINE constexpr void set_sign(Sign signVal) {362if (sign() != signVal)363bits ^= SIGN_MASK;364}365};366367// This layer defines all functions that are specific to how the the floating368// point type is encoded. It enables constructions, modification and observation369// of values manipulated as 'StorageType'.370template <FPType fp_type, typename RetT>371struct FPRepSem : public FPStorage<fp_type> {372using UP = FPStorage<fp_type>;373using typename UP::StorageType;374using UP::FRACTION_LEN;375using UP::FRACTION_MASK;376377protected:378using typename UP::Exponent;379using typename UP::Significand;380using UP::bits;381using UP::encode;382using UP::exp_bits;383using UP::exp_sig_bits;384using UP::sig_bits;385using UP::UP;386387public:388// Builders389LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) {390return RetT(encode(sign, Exponent::subnormal(), Significand::zero()));391}392LIBC_INLINE static constexpr RetT one(Sign sign = Sign::POS) {393return RetT(encode(sign, Exponent::zero(), Significand::zero()));394}395LIBC_INLINE static constexpr RetT min_subnormal(Sign sign = Sign::POS) {396return RetT(encode(sign, Exponent::subnormal(), Significand::lsb()));397}398LIBC_INLINE static constexpr RetT max_subnormal(Sign sign = Sign::POS) {399return RetT(400encode(sign, Exponent::subnormal(), Significand::bits_all_ones()));401}402LIBC_INLINE static constexpr RetT min_normal(Sign sign = Sign::POS) {403return RetT(encode(sign, Exponent::min(), Significand::zero()));404}405LIBC_INLINE static constexpr RetT max_normal(Sign sign = Sign::POS) {406return RetT(encode(sign, Exponent::max(), Significand::bits_all_ones()));407}408LIBC_INLINE static constexpr RetT inf(Sign sign = Sign::POS) {409return RetT(encode(sign, Exponent::inf(), Significand::zero()));410}411LIBC_INLINE static constexpr RetT signaling_nan(Sign sign = Sign::POS,412StorageType v = 0) {413return RetT(encode(sign, Exponent::inf(),414(v ? Significand(v) : (Significand::msb() >> 1))));415}416LIBC_INLINE static constexpr RetT quiet_nan(Sign sign = Sign::POS,417StorageType v = 0) {418return RetT(419encode(sign, Exponent::inf(), Significand::msb() | Significand(v)));420}421422// Observers423LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; }424LIBC_INLINE constexpr bool is_nan() const {425return exp_sig_bits() > encode(Exponent::inf(), Significand::zero());426}427LIBC_INLINE constexpr bool is_quiet_nan() const {428return exp_sig_bits() >= encode(Exponent::inf(), Significand::msb());429}430LIBC_INLINE constexpr bool is_signaling_nan() const {431return is_nan() && !is_quiet_nan();432}433LIBC_INLINE constexpr bool is_inf() const {434return exp_sig_bits() == encode(Exponent::inf(), Significand::zero());435}436LIBC_INLINE constexpr bool is_finite() const {437return exp_bits() != encode(Exponent::inf());438}439LIBC_INLINE440constexpr bool is_subnormal() const {441return exp_bits() == encode(Exponent::subnormal());442}443LIBC_INLINE constexpr bool is_normal() const {444return is_finite() && !is_subnormal();445}446LIBC_INLINE constexpr RetT next_toward_inf() const {447if (is_finite())448return RetT(bits + StorageType(1));449return RetT(bits);450}451452// Returns the mantissa with the implicit bit set iff the current453// value is a valid normal number.454LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {455if (is_subnormal())456return sig_bits();457return (StorageType(1) << UP::SIG_LEN) | sig_bits();458}459};460461// Specialization for the X86 Extended Precision type.462template <typename RetT>463struct FPRepSem<FPType::X86_Binary80, RetT>464: public FPStorage<FPType::X86_Binary80> {465using UP = FPStorage<FPType::X86_Binary80>;466using typename UP::StorageType;467using UP::FRACTION_LEN;468using UP::FRACTION_MASK;469470// The x86 80 bit float represents the leading digit of the mantissa471// explicitly. This is the mask for that bit.472static constexpr StorageType EXPLICIT_BIT_MASK = StorageType(1)473<< FRACTION_LEN;474// The X80 significand is made of an explicit bit and the fractional part.475static_assert((EXPLICIT_BIT_MASK & FRACTION_MASK) == 0,476"the explicit bit and the fractional part should not overlap");477static_assert((EXPLICIT_BIT_MASK | FRACTION_MASK) == SIG_MASK,478"the explicit bit and the fractional part should cover the "479"whole significand");480481protected:482using typename UP::Exponent;483using typename UP::Significand;484using UP::encode;485using UP::UP;486487public:488// Builders489LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) {490return RetT(encode(sign, Exponent::subnormal(), Significand::zero()));491}492LIBC_INLINE static constexpr RetT one(Sign sign = Sign::POS) {493return RetT(encode(sign, Exponent::zero(), Significand::msb()));494}495LIBC_INLINE static constexpr RetT min_subnormal(Sign sign = Sign::POS) {496return RetT(encode(sign, Exponent::subnormal(), Significand::lsb()));497}498LIBC_INLINE static constexpr RetT max_subnormal(Sign sign = Sign::POS) {499return RetT(encode(sign, Exponent::subnormal(),500Significand::bits_all_ones() ^ Significand::msb()));501}502LIBC_INLINE static constexpr RetT min_normal(Sign sign = Sign::POS) {503return RetT(encode(sign, Exponent::min(), Significand::msb()));504}505LIBC_INLINE static constexpr RetT max_normal(Sign sign = Sign::POS) {506return RetT(encode(sign, Exponent::max(), Significand::bits_all_ones()));507}508LIBC_INLINE static constexpr RetT inf(Sign sign = Sign::POS) {509return RetT(encode(sign, Exponent::inf(), Significand::msb()));510}511LIBC_INLINE static constexpr RetT signaling_nan(Sign sign = Sign::POS,512StorageType v = 0) {513return RetT(encode(sign, Exponent::inf(),514Significand::msb() |515(v ? Significand(v) : (Significand::msb() >> 2))));516}517LIBC_INLINE static constexpr RetT quiet_nan(Sign sign = Sign::POS,518StorageType v = 0) {519return RetT(encode(sign, Exponent::inf(),520Significand::msb() | (Significand::msb() >> 1) |521Significand(v)));522}523524// Observers525LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; }526LIBC_INLINE constexpr bool is_nan() const {527// Most encoding forms from the table found in528// https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format529// are interpreted as NaN.530// More precisely :531// - Pseudo-Infinity532// - Pseudo Not a Number533// - Signalling Not a Number534// - Floating-point Indefinite535// - Quiet Not a Number536// - Unnormal537// This can be reduced to the following logic:538if (exp_bits() == encode(Exponent::inf()))539return !is_inf();540if (exp_bits() != encode(Exponent::subnormal()))541return (sig_bits() & encode(Significand::msb())) == 0;542return false;543}544LIBC_INLINE constexpr bool is_quiet_nan() const {545return exp_sig_bits() >=546encode(Exponent::inf(),547Significand::msb() | (Significand::msb() >> 1));548}549LIBC_INLINE constexpr bool is_signaling_nan() const {550return is_nan() && !is_quiet_nan();551}552LIBC_INLINE constexpr bool is_inf() const {553return exp_sig_bits() == encode(Exponent::inf(), Significand::msb());554}555LIBC_INLINE constexpr bool is_finite() const {556return !is_inf() && !is_nan();557}558LIBC_INLINE559constexpr bool is_subnormal() const {560return exp_bits() == encode(Exponent::subnormal());561}562LIBC_INLINE constexpr bool is_normal() const {563const auto exp = exp_bits();564if (exp == encode(Exponent::subnormal()) || exp == encode(Exponent::inf()))565return false;566return get_implicit_bit();567}568LIBC_INLINE constexpr RetT next_toward_inf() const {569if (is_finite()) {570if (exp_sig_bits() == max_normal().uintval()) {571return inf(sign());572} else if (exp_sig_bits() == max_subnormal().uintval()) {573return min_normal(sign());574} else if (sig_bits() == SIG_MASK) {575return RetT(encode(sign(), ++biased_exponent(), Significand::zero()));576} else {577return RetT(bits + StorageType(1));578}579}580return RetT(bits);581}582583LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {584return sig_bits();585}586587// This functions is specific to FPRepSem<FPType::X86_Binary80>.588// TODO: Remove if possible.589LIBC_INLINE constexpr bool get_implicit_bit() const {590return static_cast<bool>(bits & EXPLICIT_BIT_MASK);591}592593// This functions is specific to FPRepSem<FPType::X86_Binary80>.594// TODO: Remove if possible.595LIBC_INLINE constexpr void set_implicit_bit(bool implicitVal) {596if (get_implicit_bit() != implicitVal)597bits ^= EXPLICIT_BIT_MASK;598}599};600601// 'FPRepImpl' is the bottom of the class hierarchy that only deals with602// 'FPType'. The operations dealing with specific float semantics are603// implemented by 'FPRepSem' above and specialized when needed.604//605// The 'RetT' type is being propagated up to 'FPRepSem' so that the functions606// creating new values (Builders) can return the appropriate type. That is, when607// creating a value through 'FPBits' below the builder will return an 'FPBits'608// value.609// FPBits<float>::zero(); // returns an FPBits<>610//611// When we don't care about specific C++ floating point type we can use612// 'FPRep' and specify the 'FPType' directly.613// FPRep<FPType::IEEE754_Binary32:>::zero() // returns an FPRep<>614template <FPType fp_type, typename RetT>615struct FPRepImpl : public FPRepSem<fp_type, RetT> {616using UP = FPRepSem<fp_type, RetT>;617using StorageType = typename UP::StorageType;618619protected:620using UP::bits;621using UP::encode;622using UP::exp_bits;623using UP::exp_sig_bits;624625using typename UP::BiasedExponent;626using typename UP::Exponent;627using typename UP::Significand;628629using UP::FP_MASK;630631public:632// Constants.633using UP::EXP_BIAS;634using UP::EXP_MASK;635using UP::FRACTION_MASK;636using UP::SIG_LEN;637using UP::SIG_MASK;638using UP::SIGN_MASK;639LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =640(1 << UP::EXP_LEN) - 1;641642// CTors643LIBC_INLINE constexpr FPRepImpl() = default;644LIBC_INLINE constexpr explicit FPRepImpl(StorageType x) : UP(x) {}645646// Comparison647LIBC_INLINE constexpr friend bool operator==(FPRepImpl a, FPRepImpl b) {648return a.uintval() == b.uintval();649}650LIBC_INLINE constexpr friend bool operator!=(FPRepImpl a, FPRepImpl b) {651return a.uintval() != b.uintval();652}653654// Representation655LIBC_INLINE constexpr StorageType uintval() const { return bits & FP_MASK; }656LIBC_INLINE constexpr void set_uintval(StorageType value) {657bits = (value & FP_MASK);658}659660// Builders661using UP::inf;662using UP::max_normal;663using UP::max_subnormal;664using UP::min_normal;665using UP::min_subnormal;666using UP::one;667using UP::quiet_nan;668using UP::signaling_nan;669using UP::zero;670671// Modifiers672LIBC_INLINE constexpr RetT abs() const {673return RetT(static_cast<StorageType>(bits & UP::EXP_SIG_MASK));674}675676// Observers677using UP::get_explicit_mantissa;678using UP::is_finite;679using UP::is_inf;680using UP::is_nan;681using UP::is_normal;682using UP::is_quiet_nan;683using UP::is_signaling_nan;684using UP::is_subnormal;685using UP::is_zero;686using UP::next_toward_inf;687using UP::sign;688LIBC_INLINE constexpr bool is_inf_or_nan() const { return !is_finite(); }689LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); }690LIBC_INLINE constexpr bool is_pos() const { return sign().is_pos(); }691692LIBC_INLINE constexpr uint16_t get_biased_exponent() const {693return static_cast<uint16_t>(static_cast<uint32_t>(UP::biased_exponent()));694}695696LIBC_INLINE constexpr void set_biased_exponent(StorageType biased) {697UP::set_biased_exponent(BiasedExponent(static_cast<uint32_t>(biased)));698}699700LIBC_INLINE constexpr int get_exponent() const {701return static_cast<int32_t>(Exponent(UP::biased_exponent()));702}703704// If the number is subnormal, the exponent is treated as if it were the705// minimum exponent for a normal number. This is to keep continuity between706// the normal and subnormal ranges, but it causes problems for functions where707// values are calculated from the exponent, since just subtracting the bias708// will give a slightly incorrect result. Additionally, zero has an exponent709// of zero, and that should actually be treated as zero.710LIBC_INLINE constexpr int get_explicit_exponent() const {711Exponent exponent(UP::biased_exponent());712if (is_zero())713exponent = Exponent::zero();714if (exponent == Exponent::subnormal())715exponent = Exponent::min();716return static_cast<int32_t>(exponent);717}718719LIBC_INLINE constexpr StorageType get_mantissa() const {720return bits & FRACTION_MASK;721}722723LIBC_INLINE constexpr void set_mantissa(StorageType mantVal) {724bits = UP::merge(bits, mantVal, FRACTION_MASK);725}726727LIBC_INLINE constexpr void set_significand(StorageType sigVal) {728bits = UP::merge(bits, sigVal, SIG_MASK);729}730// Unsafe function to create a floating point representation.731// It simply packs the sign, biased exponent and mantissa values without732// checking bound nor normalization.733//734// WARNING: For X86 Extended Precision, implicit bit needs to be set correctly735// in the 'mantissa' by the caller. This function will not check for its736// validity.737//738// FIXME: Use an uint32_t for 'biased_exp'.739LIBC_INLINE static constexpr RetT740create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {741return RetT(encode(sign, BiasedExponent(static_cast<uint32_t>(biased_exp)),742Significand(mantissa)));743}744745// The function converts integer number and unbiased exponent to proper746// float T type:747// Result = number * 2^(ep+1 - exponent_bias)748// Be careful!749// 1) "ep" is the raw exponent value.750// 2) The function adds +1 to ep for seamless normalized to denormalized751// transition.752// 3) The function does not check exponent high limit.753// 4) "number" zero value is not processed correctly.754// 5) Number is unsigned, so the result can be only positive.755LIBC_INLINE static constexpr RetT make_value(StorageType number, int ep) {756FPRepImpl result(0);757int lz =758UP::FRACTION_LEN + 1 - (UP::STORAGE_LEN - cpp::countl_zero(number));759760number <<= lz;761ep -= lz;762763if (LIBC_LIKELY(ep >= 0)) {764// Implicit number bit will be removed by mask765result.set_significand(number);766result.set_biased_exponent(static_cast<StorageType>(ep + 1));767} else {768result.set_significand(number >> static_cast<unsigned>(-ep));769}770return RetT(result.uintval());771}772};773774// A generic class to manipulate floating point formats.775// It derives its functionality to FPRepImpl above.776template <FPType fp_type>777struct FPRep : public FPRepImpl<fp_type, FPRep<fp_type>> {778using UP = FPRepImpl<fp_type, FPRep<fp_type>>;779using StorageType = typename UP::StorageType;780using UP::UP;781782LIBC_INLINE constexpr explicit operator StorageType() const {783return UP::uintval();784}785};786787} // namespace internal788789// Returns the FPType corresponding to C++ type T on the host.790template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {791using UnqualT = cpp::remove_cv_t<T>;792if constexpr (cpp::is_same_v<UnqualT, float> && __FLT_MANT_DIG__ == 24)793return FPType::IEEE754_Binary32;794else if constexpr (cpp::is_same_v<UnqualT, double> && __DBL_MANT_DIG__ == 53)795return FPType::IEEE754_Binary64;796else if constexpr (cpp::is_same_v<UnqualT, long double>) {797if constexpr (__LDBL_MANT_DIG__ == 53)798return FPType::IEEE754_Binary64;799else if constexpr (__LDBL_MANT_DIG__ == 64)800return FPType::X86_Binary80;801else if constexpr (__LDBL_MANT_DIG__ == 113)802return FPType::IEEE754_Binary128;803}804#if defined(LIBC_TYPES_HAS_FLOAT16)805else if constexpr (cpp::is_same_v<UnqualT, float16>)806return FPType::IEEE754_Binary16;807#endif808#if defined(LIBC_TYPES_HAS_FLOAT128)809else if constexpr (cpp::is_same_v<UnqualT, float128>)810return FPType::IEEE754_Binary128;811#endif812else if constexpr (cpp::is_same_v<UnqualT, bfloat16>)813return FPType::BFloat16;814else815static_assert(cpp::always_false<UnqualT>, "Unsupported type");816}817818// -----------------------------------------------------------------------------819// **** WARNING ****820// This interface is shared with libc++, if you change this interface you need821// to update it in both libc and libc++. You should also be careful when adding822// dependencies to this file, since it needs to build for all libc++ targets.823// -----------------------------------------------------------------------------824// A generic class to manipulate C++ floating point formats.825// It derives its functionality to FPRepImpl above.826template <typename T>827struct FPBits final : public internal::FPRepImpl<get_fp_type<T>(), FPBits<T>> {828static_assert(cpp::is_floating_point_v<T>,829"FPBits instantiated with invalid type.");830using UP = internal::FPRepImpl<get_fp_type<T>(), FPBits<T>>;831using StorageType = typename UP::StorageType;832833// Constructors.834LIBC_INLINE constexpr FPBits() = default;835836template <typename XType> LIBC_INLINE constexpr explicit FPBits(XType x) {837using Unqual = typename cpp::remove_cv_t<XType>;838if constexpr (cpp::is_same_v<Unqual, T>) {839UP::bits = cpp::bit_cast<StorageType>(x);840} else if constexpr (cpp::is_same_v<Unqual, StorageType>) {841UP::bits = x;842} else {843// We don't want accidental type promotions/conversions, so we require844// exact type match.845static_assert(cpp::always_false<XType>);846}847}848849// Floating-point conversions.850LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(UP::bits); }851};852853} // namespace fputil854} // namespace LIBC_NAMESPACE_DECL855856#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H857858859