[libc-commits] [libc] 952dafb - [libc][math] Add test and fix atan2f crashing when flush-denorm-to-zero (FTZ) and denorm-as-zero (DAZ) modes are set. (#112828)
via libc-commits
libc-commits at lists.llvm.org
Fri Oct 18 11:56:26 PDT 2024
Author: lntue
Date: 2024-10-18T14:56:23-04:00
New Revision: 952dafb08ed2e97c647e925bf713eddb8dc07163
URL: https://github.com/llvm/llvm-project/commit/952dafb08ed2e97c647e925bf713eddb8dc07163
DIFF: https://github.com/llvm/llvm-project/commit/952dafb08ed2e97c647e925bf713eddb8dc07163.diff
LOG: [libc][math] Add test and fix atan2f crashing when flush-denorm-to-zero (FTZ) and denorm-as-zero (DAZ) modes are set. (#112828)
Added:
Modified:
libc/src/math/generic/atan2f.cpp
libc/test/UnitTest/FPMatcher.h
libc/test/src/math/smoke/atan2f_test.cpp
Removed:
################################################################################
diff --git a/libc/src/math/generic/atan2f.cpp b/libc/src/math/generic/atan2f.cpp
index e4b297c00f012c..a2e5499809a340 100644
--- a/libc/src/math/generic/atan2f.cpp
+++ b/libc/src/math/generic/atan2f.cpp
@@ -246,12 +246,18 @@ LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
uint32_t y_abs = y_bits.uintval();
uint32_t max_abs = x_abs > y_abs ? x_abs : y_abs;
uint32_t min_abs = x_abs <= y_abs ? x_abs : y_abs;
+ float num_f = FPBits(min_abs).get_val();
+ float den_f = FPBits(max_abs).get_val();
+ double num_d = static_cast<double>(num_f);
+ double den_d = static_cast<double>(den_f);
- if (LIBC_UNLIKELY(max_abs >= 0x7f80'0000U || min_abs == 0U)) {
+ if (LIBC_UNLIKELY(max_abs >= 0x7f80'0000U || num_d == 0.0)) {
if (x_bits.is_nan() || y_bits.is_nan())
return FPBits::quiet_nan().get_val();
- size_t x_except = x_abs == 0 ? 0 : (x_abs == 0x7f80'0000 ? 2 : 1);
- size_t y_except = y_abs == 0 ? 0 : (y_abs == 0x7f80'0000 ? 2 : 1);
+ double x_d = static_cast<double>(x);
+ double y_d = static_cast<double>(y);
+ size_t x_except = (x_d == 0.0) ? 0 : (x_abs == 0x7f80'0000 ? 2 : 1);
+ size_t y_except = (y_d == 0.0) ? 0 : (y_abs == 0x7f80'0000 ? 2 : 1);
// Exceptional cases:
// EXCEPT[y_except][x_except][x_is_neg]
@@ -275,8 +281,6 @@ LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
bool recip = x_abs < y_abs;
double final_sign = IS_NEG[(x_sign != y_sign) != recip];
fputil::DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip];
- double num_d = static_cast<double>(FPBits(min_abs).get_val());
- double den_d = static_cast<double>(FPBits(max_abs).get_val());
double q_d = num_d / den_d;
double k_d = fputil::nearest_integer(q_d * 0x1.0p4f);
diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h
index 07e2cd5df18cbb..e1a33ea326ecfe 100644
--- a/libc/test/UnitTest/FPMatcher.h
+++ b/libc/test/UnitTest/FPMatcher.h
@@ -16,6 +16,7 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/fpbits_str.h"
#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
#include "test/UnitTest/RoundingModeUtils.h"
#include "test/UnitTest/StringUtils.h"
#include "test/UnitTest/Test.h"
@@ -192,6 +193,31 @@ template <typename T> struct FPTest : public Test {
};
};
+// Add facility to test Flush-Denormal-To-Zero (FTZ) and Denormal-As-Zero (DAZ)
+// modes.
+// These tests to ensure that our implementations will not crash under these
+// modes.
+#if defined(LIBC_TARGET_ARCH_IS_X86_64) && __has_builtin(__builtin_ia32_stmxcsr)
+
+#define LIBC_TEST_FTZ_DAZ
+
+static constexpr unsigned FTZ = 0x8000; // Flush denormal to zero
+static constexpr unsigned DAZ = 0x0040; // Denormal as zero
+
+struct ModifyMXCSR {
+ ModifyMXCSR(unsigned flags) {
+ old_mxcsr = __builtin_ia32_stmxcsr();
+ __builtin_ia32_ldmxcsr(old_mxcsr | flags);
+ }
+
+ ~ModifyMXCSR() { __builtin_ia32_ldmxcsr(old_mxcsr); }
+
+private:
+ unsigned old_mxcsr;
+};
+
+#endif
+
} // namespace testing
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/math/smoke/atan2f_test.cpp b/libc/test/src/math/smoke/atan2f_test.cpp
index 32a28cfdfeaa62..94ec18d8f6b143 100644
--- a/libc/test/src/math/smoke/atan2f_test.cpp
+++ b/libc/test/src/math/smoke/atan2f_test.cpp
@@ -58,3 +58,40 @@ TEST_F(LlvmLibcAtan2fTest, SpecialNumbers) {
// EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);
}
+
+#ifdef LIBC_TEST_FTZ_DAZ
+
+using namespace LIBC_NAMESPACE::testing;
+
+TEST_F(LlvmLibcAtan2fTest, FTZMode) {
+ ModifyMXCSR mxcsr(FTZ);
+
+ EXPECT_FP_EQ(0x1.921fb6p-1f,
+ LIBC_NAMESPACE::atan2f(min_denormal, min_denormal));
+ EXPECT_FP_EQ(0x1.000002p-23f,
+ LIBC_NAMESPACE::atan2f(min_denormal, max_denormal));
+ EXPECT_FP_EQ(0x1.921fb4p0f,
+ LIBC_NAMESPACE::atan2f(max_denormal, min_denormal));
+ EXPECT_FP_EQ(0x1.921fb6p-1f,
+ LIBC_NAMESPACE::atan2f(max_denormal, max_denormal));
+}
+
+TEST_F(LlvmLibcAtan2fTest, DAZMode) {
+ ModifyMXCSR mxcsr(DAZ);
+
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(min_denormal, min_denormal));
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(min_denormal, max_denormal));
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(max_denormal, min_denormal));
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(max_denormal, max_denormal));
+}
+
+TEST_F(LlvmLibcAtan2fTest, FTZDAZMode) {
+ ModifyMXCSR mxcsr(FTZ | DAZ);
+
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(min_denormal, min_denormal));
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(min_denormal, max_denormal));
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(max_denormal, min_denormal));
+ EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atan2f(max_denormal, max_denormal));
+}
+
+#endif
More information about the libc-commits
mailing list