[libc][math] Add test and fix atan2f crashing when flush-denorm-to-zero (FTZ) and denorm-as-zero (DAZ) modes are set. (#112828)
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user