[libc-commits] [libc] [libc][math] Fix incorrect logic in fputil::generic::add_or_sub (PR #116129)
via libc-commits
libc-commits at lists.llvm.org
Wed Nov 13 16:28:24 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: OverMighty (overmighty)
<details>
<summary>Changes</summary>
Fixes incorrect logic that went unnoticed until the function was tested
with output and input types having the same underlying floating-point
format. The resulting DyadicFloat's exponent was off by one when adding
two subnormal numbers, and the minimum operand's mantissa was misaligned
by one bit when adding a normal number with a subnormal number.
---
Full diff: https://github.com/llvm/llvm-project/pull/116129.diff
2 Files Affected:
- (modified) libc/src/__support/FPUtil/generic/add_sub.h (+8-7)
- (modified) libc/test/src/math/smoke/AddTest.h (+12-1)
``````````diff
diff --git a/libc/src/__support/FPUtil/generic/add_sub.h b/libc/src/__support/FPUtil/generic/add_sub.h
index 6bc9dcd23bafad..5c503e752c8ecb 100644
--- a/libc/src/__support/FPUtil/generic/add_sub.h
+++ b/libc/src/__support/FPUtil/generic/add_sub.h
@@ -160,20 +160,21 @@ add_or_sub(InType x, InType y) {
} else {
InStorageType max_mant = max_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
InStorageType min_mant = min_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
- int alignment =
- max_bits.get_biased_exponent() - min_bits.get_biased_exponent();
+
+ int alignment = (max_bits.get_biased_exponent() - max_bits.is_normal()) -
+ (min_bits.get_biased_exponent() - min_bits.is_normal());
InStorageType aligned_min_mant =
min_mant >> cpp::min(alignment, RESULT_MANTISSA_LEN);
bool aligned_min_mant_sticky;
- if (alignment <= 3)
+ if (alignment <= GUARD_BITS_LEN)
aligned_min_mant_sticky = false;
- else if (alignment <= InFPBits::FRACTION_LEN + 3)
+ else if (alignment > InFPBits::FRACTION_LEN + GUARD_BITS_LEN)
+ aligned_min_mant_sticky = true;
+ else
aligned_min_mant_sticky =
(min_mant << (InFPBits::STORAGE_LEN - alignment)) != 0;
- else
- aligned_min_mant_sticky = true;
InStorageType min_mant_sticky(static_cast<int>(aligned_min_mant_sticky));
@@ -183,7 +184,7 @@ add_or_sub(InType x, InType y) {
result_mant = max_mant - (aligned_min_mant | min_mant_sticky);
}
- int result_exp = max_bits.get_exponent() - RESULT_FRACTION_LEN;
+ int result_exp = max_bits.get_explicit_exponent() - RESULT_FRACTION_LEN;
DyadicFloat result(result_sign, result_exp, result_mant);
return result.template as<OutType, /*ShouldSignalExceptions=*/true>();
}
diff --git a/libc/test/src/math/smoke/AddTest.h b/libc/test/src/math/smoke/AddTest.h
index 66b188f4fa7b31..26efff4efaf948 100644
--- a/libc/test/src/math/smoke/AddTest.h
+++ b/libc/test/src/math/smoke/AddTest.h
@@ -136,6 +136,16 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
func(InType(1.0), in.min_denormal);
EXPECT_FP_EXCEPTION(FE_INEXACT);
}
+
+ void test_mixed_normality(AddFunc func) {
+ if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() !=
+ LIBC_NAMESPACE::fputil::get_fp_type<InType>())
+ return;
+
+ EXPECT_FP_EQ(FPBits::create_value(Sign::POS, 2U, 0b1U).get_val(),
+ func(InFPBits::create_value(Sign::POS, 2U, 0U).get_val(),
+ InFPBits::create_value(Sign::POS, 2U, 0b10U).get_val()));
+ }
};
#define LIST_ADD_TESTS(OutType, InType, func) \
@@ -145,6 +155,7 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
test_invalid_operations(&func); \
} \
TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); } \
- TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }
+ TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); } \
+ TEST_F(LlvmLibcAddTest, MixedNormality) { test_mixed_normality(&func); }
#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H
``````````
</details>
https://github.com/llvm/llvm-project/pull/116129
More information about the libc-commits
mailing list