1717#include " src/__support/common.h"
1818#include " src/__support/macros/config.h"
1919#include " src/__support/macros/optimization.h" // LIBC_UNLIKELY
20+ #include " src/__support/macros/properties/architectures.h"
21+ #include " src/__support/macros/properties/types.h"
2022#include " src/__support/uint128.h"
2123
2224namespace LIBC_NAMESPACE_DECL {
@@ -27,6 +29,86 @@ LIBC_INLINE T abs(T x) {
2729 return FPBits<T>(x).abs ().get_val ();
2830}
2931
32+ namespace internal {
33+
34+ template <typename T>
35+ LIBC_INLINE cpp::enable_if_t <cpp::is_floating_point_v<T>, T> max (T x, T y) {
36+ FPBits<T> x_bits (x);
37+ FPBits<T> y_bits (y);
38+
39+ // To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and y
40+ // have different signs and both are not NaNs, we return the number with
41+ // positive sign.
42+ if (x_bits.sign () != y_bits.sign ())
43+ return x_bits.is_pos () ? x : y;
44+ return x > y ? x : y;
45+ }
46+
47+ #if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
48+ template <> LIBC_INLINE float16 max (float16 x, float16 y) {
49+ return __builtin_fmaxf16 (x, y);
50+ }
51+ #elif !defined(LIBC_TARGET_ARCH_IS_AARCH64)
52+ template <> LIBC_INLINE float16 max (float16 x, float16 y) {
53+ FPBits<float16> x_bits (x);
54+ FPBits<float16> y_bits (y);
55+
56+ int16_t xi = static_cast <int16_t >(x_bits.uintval ());
57+ int16_t yi = static_cast <int16_t >(y_bits.uintval ());
58+ return ((xi > yi) != (xi < 0 && yi < 0 )) ? x : y;
59+ }
60+ #endif
61+
62+ #if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
63+ template <> LIBC_INLINE float max (float x, float y) {
64+ return __builtin_fmaxf (x, y);
65+ }
66+
67+ template <> LIBC_INLINE double max (double x, double y) {
68+ return __builtin_fmax (x, y);
69+ }
70+ #endif
71+
72+ template <typename T>
73+ LIBC_INLINE cpp::enable_if_t <cpp::is_floating_point_v<T>, T> min (T x, T y) {
74+ FPBits<T> x_bits (x);
75+ FPBits<T> y_bits (y);
76+
77+ // To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and y have
78+ // different signs and both are not NaNs, we return the number with negative
79+ // sign.
80+ if (x_bits.sign () != y_bits.sign ())
81+ return x_bits.is_neg () ? x : y;
82+ return x < y ? x : y;
83+ }
84+
85+ #if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
86+ template <> LIBC_INLINE float16 min (float16 x, float16 y) {
87+ return __builtin_fminf16 (x, y);
88+ }
89+ #elif !defined(LIBC_TARGET_ARCH_IS_AARCH64)
90+ template <> LIBC_INLINE float16 min (float16 x, float16 y) {
91+ FPBits<float16> x_bits (x);
92+ FPBits<float16> y_bits (y);
93+
94+ int16_t xi = static_cast <int16_t >(x_bits.uintval ());
95+ int16_t yi = static_cast <int16_t >(y_bits.uintval ());
96+ return ((xi < yi) != (xi < 0 && yi < 0 )) ? x : y;
97+ }
98+ #endif
99+
100+ #if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
101+ template <> LIBC_INLINE float min (float x, float y) {
102+ return __builtin_fminf (x, y);
103+ }
104+
105+ template <> LIBC_INLINE double min (double x, double y) {
106+ return __builtin_fmin (x, y);
107+ }
108+ #endif
109+
110+ } // namespace internal
111+
30112template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
31113LIBC_INLINE T fmin (T x, T y) {
32114 const FPBits<T> bitx (x), bity (y);
@@ -35,12 +117,7 @@ LIBC_INLINE T fmin(T x, T y) {
35117 return y;
36118 if (bity.is_nan ())
37119 return x;
38- if (bitx.sign () != bity.sign ())
39- // To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and
40- // y has different signs and both are not NaNs, we return the number
41- // with negative sign.
42- return bitx.is_neg () ? x : y;
43- return x < y ? x : y;
120+ return internal::min (x, y);
44121}
45122
46123template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
@@ -51,12 +128,7 @@ LIBC_INLINE T fmax(T x, T y) {
51128 return y;
52129 if (bity.is_nan ())
53130 return x;
54- if (bitx.sign () != bity.sign ())
55- // To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and
56- // y has different signs and both are not NaNs, we return the number
57- // with positive sign.
58- return bitx.is_neg () ? y : x;
59- return x > y ? x : y;
131+ return internal::max (x, y);
60132}
61133
62134template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
@@ -67,9 +139,7 @@ LIBC_INLINE T fmaximum(T x, T y) {
67139 return x;
68140 if (bity.is_nan ())
69141 return y;
70- if (bitx.sign () != bity.sign ())
71- return (bitx.is_neg () ? y : x);
72- return x > y ? x : y;
142+ return internal::max (x, y);
73143}
74144
75145template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
@@ -80,9 +150,7 @@ LIBC_INLINE T fminimum(T x, T y) {
80150 return x;
81151 if (bity.is_nan ())
82152 return y;
83- if (bitx.sign () != bity.sign ())
84- return (bitx.is_neg ()) ? x : y;
85- return x < y ? x : y;
153+ return internal::min (x, y);
86154}
87155
88156template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
@@ -97,9 +165,7 @@ LIBC_INLINE T fmaximum_num(T x, T y) {
97165 return y;
98166 if (bity.is_nan ())
99167 return x;
100- if (bitx.sign () != bity.sign ())
101- return (bitx.is_neg () ? y : x);
102- return x > y ? x : y;
168+ return internal::max (x, y);
103169}
104170
105171template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
@@ -114,9 +180,7 @@ LIBC_INLINE T fminimum_num(T x, T y) {
114180 return y;
115181 if (bity.is_nan ())
116182 return x;
117- if (bitx.sign () != bity.sign ())
118- return (bitx.is_neg () ? x : y);
119- return x < y ? x : y;
183+ return internal::min (x, y);
120184}
121185
122186template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
0 commit comments