[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