[libc-commits] [libc] 3b3b816 - [libc] add rounding modes to printf float conv
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Fri Jul 15 11:11:36 PDT 2022
Author: Michael Jones
Date: 2022-07-15T11:11:32-07:00
New Revision: 3b3b816f2915afc6dc55308879314baad523d4cd
URL: https://github.com/llvm/llvm-project/commit/3b3b816f2915afc6dc55308879314baad523d4cd
DIFF: https://github.com/llvm/llvm-project/commit/3b3b816f2915afc6dc55308879314baad523d4cd.diff
LOG: [libc] add rounding modes to printf float conv
This adds functionality for rounding towards negative inf, positive inf,
and zero to the float hex conversion (%a).
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D129702
Added:
Modified:
libc/src/stdio/printf_core/CMakeLists.txt
libc/src/stdio/printf_core/float_hex_converter.h
libc/test/src/stdio/CMakeLists.txt
libc/test/src/stdio/sprintf_test.cpp
Removed:
################################################################################
diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index ab94d84725396..3d22c431fe5ef 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -72,6 +72,7 @@ add_object_library(
.writer
.core_structs
libc.src.__support.CPP.limits
+ libc.src.__support.FPUtil.fputil
)
diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h
index c8c01d07824d1..a5daeaab6971d 100644
--- a/libc/src/stdio/printf_core/float_hex_converter.h
+++ b/libc/src/stdio/printf_core/float_hex_converter.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_FLOAT_HEX_CONVERTER_H
+#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/stdio/printf_core/converter_utils.h"
#include "src/stdio/printf_core/core_structs.h"
@@ -133,11 +134,25 @@ int inline convert_float_hex_exp(Writer *writer, const FormatSection &to_conv) {
mantissa >>= shift_amount;
- // Round to nearest, if it's exactly halfway then round to even.
- if (truncated_bits > halfway_const)
- ++mantissa;
- else if (truncated_bits == halfway_const)
- mantissa = mantissa + (mantissa & 1);
+ switch (fputil::get_round()) {
+ case FE_TONEAREST:
+ // Round to nearest, if it's exactly halfway then round to even.
+ if (truncated_bits > halfway_const)
+ ++mantissa;
+ else if (truncated_bits == halfway_const)
+ mantissa = mantissa + (mantissa & 1);
+ break;
+ case FE_DOWNWARD:
+ if (truncated_bits > 0 && is_negative)
+ ++mantissa;
+ break;
+ case FE_UPWARD:
+ if (truncated_bits > 0 && !is_negative)
+ ++mantissa;
+ break;
+ case FE_TOWARDZERO:
+ break;
+ }
// If the rounding caused an overflow, shift the mantissa and adjust the
// exponent to match.
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index caf7f4264cae0..2b89a3d87e67d 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -106,6 +106,8 @@ add_libc_unittest(
printf_test.cpp
DEPENDS
libc.src.stdio.printf
+ libc.src.fenv.fesetround
+ libc.src.__support.FPUtil.fputil
)
add_subdirectory(printf_core)
diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp
index 765487d90c452..1a7095a8ede14 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -11,6 +11,13 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PlatformDefs.h"
#include "utils/UnitTest/Test.h"
+#include "utils/testutils/RoundingModeUtils.h"
+
+class LlvmLibcSPrintfTest : public __llvm_libc::testing::Test {
+protected:
+ char buff[64];
+ int written;
+};
// Subtract 1 from sizeof(expected_str) to account for the null byte.
#define ASSERT_STREQ_LEN(actual_written, actual_str, expected_str) \
@@ -491,9 +498,10 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
}
#ifndef LLVM_LIBC_PRINTF_DISABLE_FLOAT
-TEST(LlvmLibcSPrintfTest, FloatHexExpConv) {
- char buff[64];
- int written;
+
+TEST_F(LlvmLibcSPrintfTest, FloatHexExpConv) {
+ __llvm_libc::testutils::ForceRoundingMode r(
+ __llvm_libc::testutils::RoundingMode::Nearest);
double inf = __llvm_libc::fputil::FPBits<double>::inf().get_val();
double nan = __llvm_libc::fputil::FPBits<double>::build_nan(1);
@@ -690,6 +698,124 @@ TEST(LlvmLibcSPrintfTest, FloatHexExpConv) {
ASSERT_STREQ_LEN(written, buff, "0x2.0p+16383");
#endif
+ // Rounding Mode Tests.
+
+ {
+ __llvm_libc::testutils::ForceRoundingMode r(
+ __llvm_libc::testutils::RoundingMode::Nearest);
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.2p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.2p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+ }
+
+ {
+ __llvm_libc::testutils::ForceRoundingMode r(
+ __llvm_libc::testutils::RoundingMode::Upward);
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.2p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.2p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+ }
+
+ {
+ __llvm_libc::testutils::ForceRoundingMode r(
+ __llvm_libc::testutils::RoundingMode::Downward);
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.2p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.2p+0");
+ }
+
+ {
+ __llvm_libc::testutils::ForceRoundingMode r(
+ __llvm_libc::testutils::RoundingMode::TowardZero);
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", 0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.08p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.18p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.04p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.0p+0");
+
+ written = __llvm_libc::sprintf(buff, "%.1a", -0x1.14p0);
+ ASSERT_STREQ_LEN(written, buff, "-0x1.1p+0");
+ }
+
// Flag Tests.
written = __llvm_libc::sprintf(buff, "%+a", nan);
More information about the libc-commits
mailing list