Skip to content

Commit 0f4b3c4

Browse files
authored
[libc][math] Add tests and fix some issues with FTZ/DAZ modes. (#113744)
1 parent 0df70c2 commit 0f4b3c4

Some content is hidden

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

56 files changed

+1135
-38
lines changed

libc/src/math/generic/atan2.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ LLVM_LIBC_FUNCTION(double, atan2, (double y, double x)) {
230230
if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) {
231231
if (x_bits.is_nan() || y_bits.is_nan())
232232
return FPBits::quiet_nan().get_val();
233-
unsigned x_except = x_abs == 0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
234-
unsigned y_except = y_abs == 0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
233+
unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
234+
unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
235235

236236
// Exceptional cases:
237237
// EXCEPT[y_except][x_except][x_is_neg]

libc/src/math/generic/cbrt.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,10 @@ LLVM_LIBC_FUNCTION(double, cbrt, (double x)) {
151151

152152
if (LIBC_UNLIKELY(x_abs < FPBits::min_normal().uintval() ||
153153
x_abs >= FPBits::inf().uintval())) {
154-
if (x_abs == 0 || x_abs >= FPBits::inf().uintval())
154+
if (x == 0.0 || x_abs >= FPBits::inf().uintval())
155155
// x is 0, Inf, or NaN.
156-
return x;
156+
// Make sure it works for FTZ/DAZ modes.
157+
return static_cast<double>(x + x);
157158

158159
// x is non-zero denormal number.
159160
// Normalize x.

libc/src/math/generic/cbrtf.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ LLVM_LIBC_FUNCTION(float, cbrtf, (float x)) {
9393
uint32_t x_abs = x_bits.uintval() & 0x7fff'ffff;
9494
uint32_t sign_bit = (x_bits.uintval() >> 31) << DoubleBits::EXP_LEN;
9595

96-
if (LIBC_UNLIKELY(x_abs == 0 || x_abs >= 0x7f80'0000)) {
96+
if (LIBC_UNLIKELY(x == 0.0f || x_abs >= 0x7f80'0000)) {
9797
// x is 0, Inf, or NaN.
98-
return x;
98+
// Make sure it works for FTZ/DAZ modes.
99+
return x + x;
99100
}
100101

101102
double xd = static_cast<double>(x);

libc/src/math/generic/log.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ LLVM_LIBC_FUNCTION(double, log, (double x)) {
749749

750750
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() ||
751751
xbits.uintval() > FPBits_t::max_normal().uintval())) {
752-
if (xbits.is_zero()) {
752+
if (x == 0.0) {
753753
// return -Inf and raise FE_DIVBYZERO.
754754
fputil::set_errno_if_required(ERANGE);
755755
fputil::raise_except_if_required(FE_DIVBYZERO);

libc/src/math/generic/log10.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ LLVM_LIBC_FUNCTION(double, log10, (double x)) {
751751

752752
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() ||
753753
xbits.uintval() > FPBits_t::max_normal().uintval())) {
754-
if (xbits.is_zero()) {
754+
if (x == 0.0) {
755755
// return -Inf and raise FE_DIVBYZERO.
756756
fputil::set_errno_if_required(ERANGE);
757757
fputil::raise_except_if_required(FE_DIVBYZERO);

libc/src/math/generic/log10f.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
164164

165165
if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() ||
166166
x_u > FPBits::max_normal().uintval())) {
167-
if (xbits.is_zero()) {
167+
if (x == 0.0f) {
168168
// Return -inf and raise FE_DIVBYZERO
169169
fputil::set_errno_if_required(ERANGE);
170170
fputil::raise_except_if_required(FE_DIVBYZERO);

libc/src/math/generic/log1p.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -927,8 +927,8 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
927927
// log(1 + x) = nextafter(x, -inf) for FE_DOWNWARD, or
928928
// FE_TOWARDZERO and x > 0,
929929
// = x otherwise.
930-
if (LIBC_UNLIKELY(xbits.is_zero()))
931-
return x;
930+
if (x == 0.0)
931+
return x + x; // Handle FTZ/DAZ correctly.
932932

933933
volatile float tp = 1.0f;
934934
volatile float tn = -1.0f;
@@ -943,7 +943,7 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
943943
return FPBits_t(x_u + 1).get_val();
944944
}
945945

946-
return x;
946+
return (x + x == 0.0) ? x + x : x;
947947
}
948948
x_dd = fputil::exact_add(1.0, x);
949949
}

libc/src/math/generic/log2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ LLVM_LIBC_FUNCTION(double, log2, (double x)) {
871871

872872
if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() ||
873873
xbits.uintval() > FPBits_t::max_normal().uintval())) {
874-
if (xbits.is_zero()) {
874+
if (x == 0.0) {
875875
// return -Inf and raise FE_DIVBYZERO.
876876
fputil::set_errno_if_required(ERANGE);
877877
fputil::raise_except_if_required(FE_DIVBYZERO);

libc/src/math/generic/log2f.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
7272
// Exceptional inputs.
7373
if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() ||
7474
x_u > FPBits::max_normal().uintval())) {
75-
if (xbits.is_zero()) {
75+
if (x == 0.0f) {
7676
fputil::set_errno_if_required(ERANGE);
7777
fputil::raise_except_if_required(FE_DIVBYZERO);
7878
return FPBits::inf(Sign::NEG).get_val();

libc/src/math/generic/logf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
8282
}
8383
// Subnormal inputs.
8484
if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval())) {
85-
if (x_u == 0) {
85+
if (x == 0.0f) {
8686
// Return -inf and raise FE_DIVBYZERO
8787
fputil::set_errno_if_required(ERANGE);
8888
fputil::raise_except_if_required(FE_DIVBYZERO);

libc/src/math/generic/pow.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,16 +228,18 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) {
228228
x_u >= FPBits::inf().uintval() ||
229229
x_u < FPBits::min_normal().uintval())) {
230230
// Exceptional exponents.
231-
switch (y_a) {
232-
case 0: // y = +-0.0
231+
if (y == 0.0)
233232
return 1.0;
233+
234+
switch (y_a) {
234235
case 0x3fe0'0000'0000'0000: { // y = +-0.5
235236
// TODO: speed up x^(-1/2) with rsqrt(x) when available.
236-
if (LIBC_UNLIKELY(!y_sign && (x_u == FPBits::zero(Sign::NEG).uintval() ||
237-
x_u == FPBits::inf(Sign::NEG).uintval()))) {
237+
if (LIBC_UNLIKELY(
238+
(x == 0.0 || x_u == FPBits::inf(Sign::NEG).uintval()))) {
238239
// pow(-0, 1/2) = +0
239240
// pow(-inf, 1/2) = +inf
240-
return FPBits(x_abs).get_val();
241+
// Make sure it works correctly for FTZ/DAZ.
242+
return y_sign ? 1.0 / (x * x) : (x * x);
241243
}
242244
return y_sign ? (1.0 / fputil::sqrt<double>(x)) : fputil::sqrt<double>(x);
243245
}
@@ -269,7 +271,7 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) {
269271
return 1.0;
270272
}
271273

272-
if (x_a == 0 && y_sign) {
274+
if (x == 0.0 && y_sign) {
273275
// pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO
274276
fputil::set_errno_if_required(EDOM);
275277
fputil::raise_except_if_required(FE_DIVBYZERO);
@@ -298,7 +300,7 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) {
298300

299301
// TODO: Speed things up with pow(2, y) = exp2(y) and pow(10, y) = exp10(y).
300302

301-
if (x_a == 0) {
303+
if (x == 0.0) {
302304
bool out_is_neg = x_sign && is_odd_integer(y);
303305
if (y_sign) {
304306
// pow(0, negative number) = inf

libc/src/math/generic/powf.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -529,10 +529,10 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
529529
// Hence x^y will either overflow or underflow if x is not zero.
530530
if (LIBC_UNLIKELY((y_abs & 0x0007'ffff) == 0) || (y_abs > 0x4f170000)) {
531531
// Exceptional exponents.
532-
switch (y_abs) {
533-
case 0x0000'0000: { // y = +-0.0f
532+
if (y == 0.0f)
534533
return 1.0f;
535-
}
534+
535+
switch (y_abs) {
536536
case 0x7f80'0000: { // y = +-Inf
537537
if (x_abs > 0x7f80'0000) {
538538
// pow(NaN, +-Inf) = NaN
@@ -542,7 +542,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
542542
// pow(+-1, +-Inf) = 1.0f
543543
return 1.0f;
544544
}
545-
if (x_abs == 0 && y_u == 0xff80'0000) {
545+
if (x == 0.0f && y_u == 0xff80'0000) {
546546
// pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO
547547
fputil::set_errno_if_required(EDOM);
548548
fputil::raise_except_if_required(FE_DIVBYZERO);
@@ -561,12 +561,15 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
561561
switch (y_u) {
562562
case 0x3f00'0000: // y = 0.5f
563563
// pow(x, 1/2) = sqrt(x)
564-
if (LIBC_UNLIKELY(x_u == 0x8000'0000 || x_u == 0xff80'0000)) {
564+
if (LIBC_UNLIKELY(x == 0.0f || x_u == 0xff80'0000)) {
565565
// pow(-0, 1/2) = +0
566566
// pow(-inf, 1/2) = +inf
567-
return FloatBits(x_abs).get_val();
567+
// Make sure it is correct for FTZ/DAZ.
568+
return x * x;
568569
}
569-
return fputil::sqrt<float>(x);
570+
float r;
571+
r = fputil::sqrt<float>(x);
572+
return (FloatBits(r).uintval() != 0x8000'0000) ? r : 0.0f;
570573
case 0x3f80'0000: // y = 1.0f
571574
return x;
572575
case 0x4000'0000: // y = 2.0f
@@ -634,8 +637,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
634637

635638
const bool x_is_neg = x_u >= FloatBits::SIGN_MASK;
636639

637-
switch (x_abs) {
638-
case 0x0000'0000: { // x = +-0.0f
640+
if (x == 0.0f) {
639641
const bool out_is_neg =
640642
x_is_neg && is_odd_integer(FloatBits(y_u).get_val());
641643
if (y_u > 0x8000'0000U) {
@@ -647,15 +649,16 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
647649
// pow(0, positive number) = 0
648650
return out_is_neg ? -0.0f : 0.0f;
649651
}
650-
case 0x7f80'0000: { // x = +-Inf
652+
653+
if (x_abs == 0x7f80'0000) {
654+
// x = +-Inf
651655
const bool out_is_neg =
652656
x_is_neg && is_odd_integer(FloatBits(y_u).get_val());
653657
if (y_u >= FloatBits::SIGN_MASK) {
654658
return out_is_neg ? -0.0f : 0.0f;
655659
}
656660
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS).get_val();
657661
}
658-
}
659662

660663
if (x_abs > 0x7f80'0000) {
661664
// x is NaN.

libc/src/math/generic/sin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ LLVM_LIBC_FUNCTION(double, sin, (double x)) {
5050
if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 26)) {
5151
// Signed zeros.
5252
if (LIBC_UNLIKELY(x == 0.0))
53-
return x;
53+
return x + x; // Make sure it works with FTZ/DAZ.
5454

5555
#ifdef LIBC_TARGET_CPU_HAS_FMA
5656
return fputil::multiply_add(x, -0x1.0p-54, x);

libc/src/math/generic/tan.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ LLVM_LIBC_FUNCTION(double, tan, (double x)) {
138138
if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 27)) {
139139
// Signed zeros.
140140
if (LIBC_UNLIKELY(x == 0.0))
141-
return x;
141+
return x + x; // Make sure it works with FTZ/DAZ.
142142

143143
#ifdef LIBC_TARGET_CPU_HAS_FMA
144144
return fputil::multiply_add(x, 0x1.0p-54, x);

libc/test/src/math/smoke/HypotTest.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@
1414
#include "test/UnitTest/Test.h"
1515

1616
template <typename T>
17-
class HypotTestTemplate : public LIBC_NAMESPACE::testing::Test {
18-
private:
17+
struct HypotTestTemplate : public LIBC_NAMESPACE::testing::Test {
1918
using Func = T (*)(T, T);
2019

2120
DECLARE_SPECIAL_CONSTANTS(T)
2221

23-
public:
2422
void test_special_numbers(Func func) {
2523
constexpr int N = 4;
2624
// Pythagorean triples.

libc/test/src/math/smoke/acosf_test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,27 @@ TEST_F(LlvmLibcAcosfTest, SpecialNumbers) {
3838
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acosf(-2.0f));
3939
EXPECT_MATH_ERRNO(EDOM);
4040
}
41+
42+
#ifdef LIBC_TEST_FTZ_DAZ
43+
44+
using namespace LIBC_NAMESPACE::testing;
45+
46+
TEST_F(LlvmLibcAcosfTest, FTZMode) {
47+
ModifyMXCSR mxcsr(FTZ);
48+
49+
EXPECT_FP_EQ(0x1.921fb6p0f, LIBC_NAMESPACE::acosf(min_denormal));
50+
}
51+
52+
TEST_F(LlvmLibcAcosfTest, DAZMode) {
53+
ModifyMXCSR mxcsr(DAZ);
54+
55+
EXPECT_FP_EQ(0x1.921fb6p0f, LIBC_NAMESPACE::acosf(min_denormal));
56+
}
57+
58+
TEST_F(LlvmLibcAcosfTest, FTZDAZMode) {
59+
ModifyMXCSR mxcsr(FTZ | DAZ);
60+
61+
EXPECT_FP_EQ(0x1.921fb6p0f, LIBC_NAMESPACE::acosf(min_denormal));
62+
}
63+
64+
#endif

libc/test/src/math/smoke/acoshf_test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,27 @@ TEST_F(LlvmLibcAcoshfTest, SpecialNumbers) {
3535
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acoshf(neg_inf));
3636
EXPECT_MATH_ERRNO(EDOM);
3737
}
38+
39+
#ifdef LIBC_TEST_FTZ_DAZ
40+
41+
using namespace LIBC_NAMESPACE::testing;
42+
43+
TEST_F(LlvmLibcAcoshfTest, FTZMode) {
44+
ModifyMXCSR mxcsr(FTZ);
45+
46+
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::acoshf(min_denormal));
47+
}
48+
49+
TEST_F(LlvmLibcAcoshfTest, DAZMode) {
50+
ModifyMXCSR mxcsr(DAZ);
51+
52+
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::acoshf(min_denormal));
53+
}
54+
55+
TEST_F(LlvmLibcAcoshfTest, FTZDAZMode) {
56+
ModifyMXCSR mxcsr(FTZ | DAZ);
57+
58+
EXPECT_FP_IS_NAN(LIBC_NAMESPACE::acoshf(min_denormal));
59+
}
60+
61+
#endif

libc/test/src/math/smoke/asinf_test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,27 @@ TEST_F(LlvmLibcAsinfTest, SpecialNumbers) {
4141
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::asinf(-2.0f));
4242
EXPECT_MATH_ERRNO(EDOM);
4343
}
44+
45+
#ifdef LIBC_TEST_FTZ_DAZ
46+
47+
using namespace LIBC_NAMESPACE::testing;
48+
49+
TEST_F(LlvmLibcAsinfTest, FTZMode) {
50+
ModifyMXCSR mxcsr(FTZ);
51+
52+
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinf(min_denormal));
53+
}
54+
55+
TEST_F(LlvmLibcAsinfTest, DAZMode) {
56+
ModifyMXCSR mxcsr(DAZ);
57+
58+
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinf(min_denormal));
59+
}
60+
61+
TEST_F(LlvmLibcAsinfTest, FTZDAZMode) {
62+
ModifyMXCSR mxcsr(FTZ | DAZ);
63+
64+
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinf(min_denormal));
65+
}
66+
67+
#endif

libc/test/src/math/smoke/asinhf_test.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,27 @@ TEST_F(LlvmLibcAsinhfTest, SpecialNumbers) {
3535
EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, LIBC_NAMESPACE::asinhf(neg_inf));
3636
EXPECT_MATH_ERRNO(0);
3737
}
38+
39+
#ifdef LIBC_TEST_FTZ_DAZ
40+
41+
using namespace LIBC_NAMESPACE::testing;
42+
43+
TEST_F(LlvmLibcAsinhfTest, FTZMode) {
44+
ModifyMXCSR mxcsr(FTZ);
45+
46+
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf(min_denormal));
47+
}
48+
49+
TEST_F(LlvmLibcAsinhfTest, DAZMode) {
50+
ModifyMXCSR mxcsr(DAZ);
51+
52+
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf(min_denormal));
53+
}
54+
55+
TEST_F(LlvmLibcAsinhfTest, FTZDAZMode) {
56+
ModifyMXCSR mxcsr(FTZ | DAZ);
57+
58+
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf(min_denormal));
59+
}
60+
61+
#endif

0 commit comments

Comments
 (0)