17
17
#include " src/__support/common.h"
18
18
#include " src/__support/macros/config.h"
19
19
#include " src/__support/macros/optimization.h" // LIBC_UNLIKELY
20
+ #include " src/__support/macros/properties/architectures.h"
21
+ #include " src/__support/macros/properties/types.h"
20
22
#include " src/__support/uint128.h"
21
23
22
24
namespace LIBC_NAMESPACE_DECL {
@@ -27,6 +29,86 @@ LIBC_INLINE T abs(T x) {
27
29
return FPBits<T>(x).abs ().get_val ();
28
30
}
29
31
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
+
30
112
template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
31
113
LIBC_INLINE T fmin (T x, T y) {
32
114
const FPBits<T> bitx (x), bity (y);
@@ -35,12 +117,7 @@ LIBC_INLINE T fmin(T x, T y) {
35
117
return y;
36
118
if (bity.is_nan ())
37
119
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);
44
121
}
45
122
46
123
template <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) {
51
128
return y;
52
129
if (bity.is_nan ())
53
130
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);
60
132
}
61
133
62
134
template <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) {
67
139
return x;
68
140
if (bity.is_nan ())
69
141
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);
73
143
}
74
144
75
145
template <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) {
80
150
return x;
81
151
if (bity.is_nan ())
82
152
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);
86
154
}
87
155
88
156
template <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) {
97
165
return y;
98
166
if (bity.is_nan ())
99
167
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);
103
169
}
104
170
105
171
template <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) {
114
180
return y;
115
181
if (bity.is_nan ())
116
182
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);
120
184
}
121
185
122
186
template <typename T, cpp::enable_if_t <cpp::is_floating_point_v<T>, int > = 0 >
0 commit comments