Skip to content

Commit 11ec512

Browse files
authored
[libc][NFC] Introduce a Sign type for FPBits (#78500)
Another patch is needed to cover `DyadicFloat` and `NormalFloat` constructors.
1 parent 9acc404 commit 11ec512

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+427
-372
lines changed

libc/src/__support/FPUtil/BasicOperations.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,23 @@ namespace fputil {
2020
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
2121
LIBC_INLINE T abs(T x) {
2222
FPBits<T> bits(x);
23-
bits.set_sign(0);
23+
bits.set_sign(Sign::POS);
2424
return T(bits);
2525
}
2626

2727
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
2828
LIBC_INLINE T fmin(T x, T y) {
29-
FPBits<T> bitx(x), bity(y);
29+
const FPBits<T> bitx(x), bity(y);
3030

3131
if (bitx.is_nan()) {
3232
return y;
3333
} else if (bity.is_nan()) {
3434
return x;
35-
} else if (bitx.get_sign() != bity.get_sign()) {
35+
} else if (bitx.sign() != bity.sign()) {
3636
// To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and
3737
// y has different signs and both are not NaNs, we return the number
3838
// with negative sign.
39-
return (bitx.get_sign() ? x : y);
39+
return (bitx.is_neg()) ? x : y;
4040
} else {
4141
return (x < y ? x : y);
4242
}
@@ -50,11 +50,11 @@ LIBC_INLINE T fmax(T x, T y) {
5050
return y;
5151
} else if (bity.is_nan()) {
5252
return x;
53-
} else if (bitx.get_sign() != bity.get_sign()) {
53+
} else if (bitx.sign() != bity.sign()) {
5454
// To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and
5555
// y has different signs and both are not NaNs, we return the number
5656
// with positive sign.
57-
return (bitx.get_sign() ? y : x);
57+
return (bitx.is_neg() ? y : x);
5858
} else {
5959
return (x > y ? x : y);
6060
}

libc/src/__support/FPUtil/DivisionAndRemainderOperations.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,14 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
4343
return x;
4444
}
4545

46-
bool result_sign = (xbits.get_sign() == ybits.get_sign() ? false : true);
46+
const Sign result_sign =
47+
(xbits.sign() == ybits.sign() ? Sign::POS : Sign::NEG);
4748

4849
// Once we know the sign of the result, we can just operate on the absolute
4950
// values. The correct sign can be applied to the result after the result
5051
// is evaluated.
51-
xbits.set_sign(0);
52-
ybits.set_sign(0);
52+
xbits.set_sign(Sign::POS);
53+
ybits.set_sign(Sign::POS);
5354

5455
NormalFloat<T> normalx(xbits), normaly(ybits);
5556
int exp = normalx.exponent - normaly.exponent;
@@ -72,7 +73,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
7273

7374
mx = n - my;
7475
if (mx == 0) {
75-
q = result_sign ? -q : q;
76+
q = result_sign.is_neg() ? -q : q;
7677
return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
7778
}
7879
}
@@ -107,7 +108,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
107108
native_remainder = -native_remainder;
108109
}
109110

110-
q = result_sign ? -q : q;
111+
q = result_sign.is_neg() ? -q : q;
111112
if (native_remainder == T(0.0))
112113
return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
113114
return native_remainder;

libc/src/__support/FPUtil/FPBits.h

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,32 @@ enum class FPType {
3131
X86_Binary80,
3232
};
3333

34+
// A type to interact with floating point type signs.
35+
// This may be moved outside of 'fputil' if useful.
36+
struct Sign {
37+
LIBC_INLINE constexpr bool is_pos() const { return !is_negative; }
38+
LIBC_INLINE constexpr bool is_neg() const { return is_negative; }
39+
40+
LIBC_INLINE friend constexpr bool operator==(Sign a, Sign b) {
41+
return a.is_negative == b.is_negative;
42+
}
43+
LIBC_INLINE friend constexpr bool operator!=(Sign a, Sign b) {
44+
return !(a == b);
45+
}
46+
47+
static const Sign POS;
48+
static const Sign NEG;
49+
50+
private:
51+
LIBC_INLINE constexpr explicit Sign(bool is_negative)
52+
: is_negative(is_negative) {}
53+
54+
bool is_negative;
55+
};
56+
57+
LIBC_INLINE_VAR constexpr Sign Sign::NEG = Sign(true);
58+
LIBC_INLINE_VAR constexpr Sign Sign::POS = Sign(false);
59+
3460
// The classes hierarchy is as follows:
3561
//
3662
// ┌───────────────────┐
@@ -273,9 +299,9 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
273299
return encode(exp) | encode(sig);
274300
}
275301

276-
LIBC_INLINE static constexpr StorageType encode(bool sign, BiasedExponent exp,
302+
LIBC_INLINE static constexpr StorageType encode(Sign sign, BiasedExponent exp,
277303
Significand sig) {
278-
if (sign)
304+
if (sign.is_neg())
279305
return SIGN_MASK | encode(exp, sig);
280306
return encode(exp, sig);
281307
}
@@ -309,12 +335,12 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
309335
StorageType bits = 0;
310336

311337
public:
312-
LIBC_INLINE constexpr bool get_sign() const {
313-
return (bits & SIGN_MASK) != 0;
338+
LIBC_INLINE constexpr Sign sign() const {
339+
return (bits & SIGN_MASK) ? Sign::NEG : Sign::POS;
314340
}
315341

316-
LIBC_INLINE constexpr void set_sign(bool signVal) {
317-
if (get_sign() != signVal)
342+
LIBC_INLINE constexpr void set_sign(Sign signVal) {
343+
if (sign() != signVal)
318344
bits ^= SIGN_MASK;
319345
}
320346

@@ -363,6 +389,9 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
363389
LIBC_INLINE constexpr bool is_zero() const {
364390
return (bits & EXP_SIG_MASK) == 0;
365391
}
392+
393+
LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); }
394+
LIBC_INLINE constexpr bool is_pos() const { return sign().is_pos(); }
366395
};
367396

368397
namespace internal {
@@ -421,35 +450,37 @@ template <FPType fp_type> struct FPRep : public FPRepBase<fp_type> {
421450
return is_finite() && !is_subnormal();
422451
}
423452

424-
LIBC_INLINE static constexpr StorageType zero(bool sign = false) {
453+
LIBC_INLINE static constexpr StorageType zero(Sign sign = Sign::POS) {
425454
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
426455
}
427-
LIBC_INLINE static constexpr StorageType one(bool sign = false) {
456+
LIBC_INLINE static constexpr StorageType one(Sign sign = Sign::POS) {
428457
return encode(sign, Exponent::ZERO(), Significand::ZERO());
429458
}
430-
LIBC_INLINE static constexpr StorageType min_subnormal(bool sign = false) {
459+
LIBC_INLINE static constexpr StorageType
460+
min_subnormal(Sign sign = Sign::POS) {
431461
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::LSB());
432462
}
433-
LIBC_INLINE static constexpr StorageType max_subnormal(bool sign = false) {
463+
LIBC_INLINE static constexpr StorageType
464+
max_subnormal(Sign sign = Sign::POS) {
434465
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(),
435466
Significand::BITS_ALL_ONES());
436467
}
437-
LIBC_INLINE static constexpr StorageType min_normal(bool sign = false) {
468+
LIBC_INLINE static constexpr StorageType min_normal(Sign sign = Sign::POS) {
438469
return encode(sign, Exponent::MIN(), Significand::ZERO());
439470
}
440-
LIBC_INLINE static constexpr StorageType max_normal(bool sign = false) {
471+
LIBC_INLINE static constexpr StorageType max_normal(Sign sign = Sign::POS) {
441472
return encode(sign, Exponent::MAX(), Significand::BITS_ALL_ONES());
442473
}
443-
LIBC_INLINE static constexpr StorageType inf(bool sign = false) {
474+
LIBC_INLINE static constexpr StorageType inf(Sign sign = Sign::POS) {
444475
return encode(sign, BiasedExponent::BITS_ALL_ONES(), Significand::ZERO());
445476
}
446-
LIBC_INLINE static constexpr StorageType build_nan(bool sign = false,
477+
LIBC_INLINE static constexpr StorageType build_nan(Sign sign = Sign::POS,
447478
StorageType v = 0) {
448479
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
449480
(v ? Significand(v) : (Significand::MSB() >> 1)));
450481
}
451-
LIBC_INLINE static constexpr StorageType build_quiet_nan(bool sign = false,
452-
StorageType v = 0) {
482+
LIBC_INLINE static constexpr StorageType
483+
build_quiet_nan(Sign sign = Sign::POS, StorageType v = 0) {
453484
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
454485
Significand::MSB() | Significand(v));
455486
}
@@ -539,36 +570,38 @@ struct FPRep<FPType::X86_Binary80> : public FPRepBase<FPType::X86_Binary80> {
539570
return get_implicit_bit();
540571
}
541572

542-
LIBC_INLINE static constexpr StorageType zero(bool sign = false) {
573+
LIBC_INLINE static constexpr StorageType zero(Sign sign = Sign::POS) {
543574
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
544575
}
545-
LIBC_INLINE static constexpr StorageType one(bool sign = false) {
576+
LIBC_INLINE static constexpr StorageType one(Sign sign = Sign::POS) {
546577
return encode(sign, Exponent::ZERO(), Significand::MSB());
547578
}
548-
LIBC_INLINE static constexpr StorageType min_subnormal(bool sign = false) {
579+
LIBC_INLINE static constexpr StorageType
580+
min_subnormal(Sign sign = Sign::POS) {
549581
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::LSB());
550582
}
551-
LIBC_INLINE static constexpr StorageType max_subnormal(bool sign = false) {
583+
LIBC_INLINE static constexpr StorageType
584+
max_subnormal(Sign sign = Sign::POS) {
552585
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(),
553586
Significand::BITS_ALL_ONES() ^ Significand::MSB());
554587
}
555-
LIBC_INLINE static constexpr StorageType min_normal(bool sign = false) {
588+
LIBC_INLINE static constexpr StorageType min_normal(Sign sign = Sign::POS) {
556589
return encode(sign, Exponent::MIN(), Significand::MSB());
557590
}
558-
LIBC_INLINE static constexpr StorageType max_normal(bool sign = false) {
591+
LIBC_INLINE static constexpr StorageType max_normal(Sign sign = Sign::POS) {
559592
return encode(sign, Exponent::MAX(), Significand::BITS_ALL_ONES());
560593
}
561-
LIBC_INLINE static constexpr StorageType inf(bool sign = false) {
594+
LIBC_INLINE static constexpr StorageType inf(Sign sign = Sign::POS) {
562595
return encode(sign, BiasedExponent::BITS_ALL_ONES(), Significand::MSB());
563596
}
564-
LIBC_INLINE static constexpr StorageType build_nan(bool sign = false,
597+
LIBC_INLINE static constexpr StorageType build_nan(Sign sign = Sign::POS,
565598
StorageType v = 0) {
566599
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
567600
Significand::MSB() |
568601
(v ? Significand(v) : (Significand::MSB() >> 2)));
569602
}
570-
LIBC_INLINE static constexpr StorageType build_quiet_nan(bool sign = false,
571-
StorageType v = 0) {
603+
LIBC_INLINE static constexpr StorageType
604+
build_quiet_nan(Sign sign = Sign::POS, StorageType v = 0) {
572605
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
573606
Significand::MSB() | (Significand::MSB() >> 1) |
574607
Significand(v));
@@ -642,10 +675,10 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
642675

643676
// Constants.
644677
static constexpr int MAX_BIASED_EXPONENT = (1 << EXP_LEN) - 1;
645-
static constexpr StorageType MIN_NORMAL = UP::min_normal(false);
646-
static constexpr StorageType MAX_NORMAL = UP::max_normal(false);
647-
static constexpr StorageType MIN_SUBNORMAL = UP::min_subnormal(false);
648-
static constexpr StorageType MAX_SUBNORMAL = UP::max_subnormal(false);
678+
static constexpr StorageType MIN_NORMAL = UP::min_normal(Sign::POS);
679+
static constexpr StorageType MAX_NORMAL = UP::max_normal(Sign::POS);
680+
static constexpr StorageType MIN_SUBNORMAL = UP::min_subnormal(Sign::POS);
681+
static constexpr StorageType MAX_SUBNORMAL = UP::max_subnormal(Sign::POS);
649682

650683
// Constructors.
651684
LIBC_INLINE constexpr FPBits() = default;
@@ -675,45 +708,46 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
675708

676709
// Methods below this are used by tests.
677710

678-
LIBC_INLINE static constexpr T zero(bool sign = false) {
679-
return FPBits(UP::zero(sign)).get_val();
711+
LIBC_INLINE static constexpr T one(Sign sign = Sign::POS) {
712+
return FPBits(UP::one(sign)).get_val();
680713
}
681714

682-
LIBC_INLINE static constexpr T neg_zero() { return zero(true); }
715+
LIBC_INLINE static constexpr T zero(Sign sign = Sign::POS) {
716+
return FPBits(UP::zero(sign)).get_val();
717+
}
683718

684-
LIBC_INLINE static constexpr T inf(bool sign = false) {
719+
LIBC_INLINE static constexpr T inf(Sign sign = Sign::POS) {
685720
return FPBits(UP::inf(sign)).get_val();
686721
}
687722

688-
LIBC_INLINE static constexpr T neg_inf() { return inf(true); }
689-
690723
LIBC_INLINE static constexpr T min_normal() {
691-
return FPBits(UP::min_normal(false)).get_val();
724+
return FPBits(UP::min_normal(Sign::POS)).get_val();
692725
}
693726

694727
LIBC_INLINE static constexpr T max_normal() {
695-
return FPBits(UP::max_normal(false)).get_val();
728+
return FPBits(UP::max_normal(Sign::POS)).get_val();
696729
}
697730

698731
LIBC_INLINE static constexpr T min_denormal() {
699-
return FPBits(UP::min_subnormal(false)).get_val();
732+
return FPBits(UP::min_subnormal(Sign::POS)).get_val();
700733
}
701734

702735
LIBC_INLINE static constexpr T max_denormal() {
703-
return FPBits(UP::max_subnormal(false)).get_val();
736+
return FPBits(UP::max_subnormal(Sign::POS)).get_val();
704737
}
705738

706739
LIBC_INLINE static constexpr T build_nan(StorageType v) {
707-
return FPBits(UP::build_nan(false, v)).get_val();
740+
return FPBits(UP::build_nan(Sign::POS, v)).get_val();
708741
}
709742

710-
LIBC_INLINE static constexpr T build_quiet_nan(StorageType v) {
711-
return FPBits(UP::build_quiet_nan(false, v)).get_val();
743+
LIBC_INLINE static constexpr T build_quiet_nan(StorageType v,
744+
Sign sign = Sign::POS) {
745+
return FPBits(UP::build_quiet_nan(sign, v)).get_val();
712746
}
713747

714748
// TODO: Use an uint32_t for 'biased_exp'.
715749
LIBC_INLINE static constexpr FPBits<T>
716-
create_value(bool sign, StorageType biased_exp, StorageType mantissa) {
750+
create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {
717751
static_assert(get_fp_type<T>() != FPType::X86_Binary80,
718752
"This function is not tested for X86 Extended Precision");
719753
return FPBits(UP::encode(

libc/src/__support/FPUtil/ManipulationFunctions.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ LIBC_INLINE T modf(T x, T &iptr) {
4949
return x;
5050
} else if (bits.is_inf()) {
5151
iptr = x;
52-
return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
52+
return T(FPBits<T>::zero(bits.sign()));
5353
} else {
5454
iptr = trunc(x);
5555
if (x == iptr) {
5656
// If x is already an integer value, then return zero with the right
5757
// sign.
58-
return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
58+
return T(FPBits<T>::zero(bits.sign()));
5959
} else {
6060
return x - iptr;
6161
}
@@ -65,7 +65,7 @@ LIBC_INLINE T modf(T x, T &iptr) {
6565
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
6666
LIBC_INLINE T copysign(T x, T y) {
6767
FPBits<T> xbits(x);
68-
xbits.set_sign(FPBits<T>(y).get_sign());
68+
xbits.set_sign(FPBits<T>(y).sign());
6969
return T(xbits);
7070
}
7171

@@ -103,12 +103,12 @@ LIBC_INLINE T logb(T x) {
103103
if (bits.is_zero()) {
104104
// TODO(Floating point exception): Raise div-by-zero exception.
105105
// TODO(errno): POSIX requires setting errno to ERANGE.
106-
return T(FPBits<T>::neg_inf());
106+
return T(FPBits<T>::inf(Sign::NEG));
107107
} else if (bits.is_nan()) {
108108
return x;
109109
} else if (bits.is_inf()) {
110110
// Return positive infinity.
111-
return T(FPBits<T>::inf());
111+
return T(FPBits<T>::inf(Sign::POS));
112112
}
113113

114114
NormalFloat<T> normal(bits);
@@ -131,11 +131,11 @@ LIBC_INLINE T ldexp(T x, int exp) {
131131
// calculating the limit.
132132
int exp_limit = FPBits<T>::MAX_BIASED_EXPONENT + FPBits<T>::FRACTION_LEN + 1;
133133
if (exp > exp_limit)
134-
return bits.get_sign() ? T(FPBits<T>::neg_inf()) : T(FPBits<T>::inf());
134+
return T(FPBits<T>::inf(bits.sign()));
135135

136136
// Similarly on the negative side we return zero early if |exp| is too small.
137137
if (exp < -exp_limit)
138-
return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
138+
return T(FPBits<T>::zero(bits.sign()));
139139

140140
// For all other values, NormalFloat to T conversion handles it the right way.
141141
NormalFloat<T> normal(bits);
@@ -173,7 +173,7 @@ LIBC_INLINE T nextafter(T from, U to) {
173173
}
174174
} else {
175175
int_val = FPBits<T>::MIN_SUBNORMAL;
176-
if (to_bits.get_sign())
176+
if (to_bits.is_neg())
177177
int_val |= FPBits<T>::SIGN_MASK;
178178
}
179179

0 commit comments

Comments
 (0)