Skip to content

[libc][math][c23] Add {,u}fromfp{,x}{,f,l,f128} functions #86003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 25, 2024

Conversation

overmighty
Copy link
Member

Fixes #85279.

cc @lntue

@overmighty overmighty requested a review from rupprecht as a code owner March 20, 2024 20:47
@llvmbot llvmbot added libc bazel "Peripheral" support tier build system: utils/bazel labels Mar 20, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 20, 2024

@llvm/pr-subscribers-libc

Author: OverMighty (overmighty)

Changes

Fixes #85279.

cc @lntue


Patch is 143.85 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/86003.diff

63 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+16)
  • (modified) libc/docs/math/index.rst (+32)
  • (modified) libc/include/llvm-libc-macros/math-macros.h (+6)
  • (modified) libc/spec/stdc.td (+26)
  • (modified) libc/src/__support/FPUtil/NearestIntegerOperations.h (+76-14)
  • (modified) libc/src/math/CMakeLists.txt (+20)
  • (added) libc/src/math/fromfp.h (+18)
  • (added) libc/src/math/fromfpf.h (+18)
  • (added) libc/src/math/fromfpf128.h (+20)
  • (added) libc/src/math/fromfpl.h (+18)
  • (added) libc/src/math/fromfpx.h (+18)
  • (added) libc/src/math/fromfpxf.h (+18)
  • (added) libc/src/math/fromfpxf128.h (+20)
  • (added) libc/src/math/fromfpxl.h (+18)
  • (modified) libc/src/math/generic/CMakeLists.txt (+196)
  • (added) libc/src/math/generic/fromfp.cpp (+19)
  • (added) libc/src/math/generic/fromfpf.cpp (+19)
  • (added) libc/src/math/generic/fromfpf128.cpp (+20)
  • (added) libc/src/math/generic/fromfpl.cpp (+20)
  • (added) libc/src/math/generic/fromfpx.cpp (+19)
  • (added) libc/src/math/generic/fromfpxf.cpp (+19)
  • (added) libc/src/math/generic/fromfpxf128.cpp (+20)
  • (added) libc/src/math/generic/fromfpxl.cpp (+20)
  • (added) libc/src/math/generic/ufromfp.cpp (+19)
  • (added) libc/src/math/generic/ufromfpf.cpp (+19)
  • (added) libc/src/math/generic/ufromfpf128.cpp (+20)
  • (added) libc/src/math/generic/ufromfpl.cpp (+20)
  • (added) libc/src/math/generic/ufromfpx.cpp (+19)
  • (added) libc/src/math/generic/ufromfpxf.cpp (+19)
  • (added) libc/src/math/generic/ufromfpxf128.cpp (+20)
  • (added) libc/src/math/generic/ufromfpxl.cpp (+20)
  • (added) libc/src/math/ufromfp.h (+18)
  • (added) libc/src/math/ufromfpf.h (+18)
  • (added) libc/src/math/ufromfpf128.h (+20)
  • (added) libc/src/math/ufromfpl.h (+18)
  • (added) libc/src/math/ufromfpx.h (+18)
  • (added) libc/src/math/ufromfpxf.h (+18)
  • (added) libc/src/math/ufromfpxf128.h (+20)
  • (added) libc/src/math/ufromfpxl.h (+18)
  • (modified) libc/test/UnitTest/CMakeLists.txt (+1)
  • (modified) libc/test/UnitTest/FPMatcher.h (+8-1)
  • (modified) libc/test/src/math/smoke/CMakeLists.txt (+192)
  • (added) libc/test/src/math/smoke/FromfpTest.h (+338)
  • (added) libc/test/src/math/smoke/FromfpxTest.h (+452)
  • (added) libc/test/src/math/smoke/UfromfpTest.h (+288)
  • (added) libc/test/src/math/smoke/UfromfpxTest.h (+353)
  • (added) libc/test/src/math/smoke/fromfp_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpf128_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpf_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpl_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpx_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpxf128_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpxf_test.cpp (+13)
  • (added) libc/test/src/math/smoke/fromfpxl_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfp_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpf128_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpf_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpl_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpx_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpxf128_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpxf_test.cpp (+13)
  • (added) libc/test/src/math/smoke/ufromfpxl_test.cpp (+13)
  • (modified) utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel (+1)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e8cf11266624a7..d17240ab8de521 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -383,6 +383,12 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.frexp
     libc.src.math.frexpf
     libc.src.math.frexpl
+    libc.src.math.fromfp
+    libc.src.math.fromfpf
+    libc.src.math.fromfpl
+    libc.src.math.fromfpx
+    libc.src.math.fromfpxf
+    libc.src.math.fromfpxl
     libc.src.math.hypot
     libc.src.math.hypotf
     libc.src.math.ilogb
@@ -467,6 +473,12 @@ set(TARGET_LIBM_ENTRYPOINTS
     libc.src.math.trunc
     libc.src.math.truncf
     libc.src.math.truncl
+    libc.src.math.ufromfp
+    libc.src.math.ufromfpf
+    libc.src.math.ufromfpl
+    libc.src.math.ufromfpx
+    libc.src.math.ufromfpxf
+    libc.src.math.ufromfpxl
 )
 
 if(LIBC_TYPES_HAS_FLOAT128)
@@ -481,6 +493,8 @@ if(LIBC_TYPES_HAS_FLOAT128)
     libc.src.math.fminf128
     libc.src.math.fmodf128
     libc.src.math.frexpf128
+    libc.src.math.fromfpf128
+    libc.src.math.fromfpxf128
     libc.src.math.ilogbf128
     libc.src.math.ldexpf128
     libc.src.math.llogbf128
@@ -498,6 +512,8 @@ if(LIBC_TYPES_HAS_FLOAT128)
     libc.src.math.roundf128
     libc.src.math.sqrtf128
     libc.src.math.truncf128
+    libc.src.math.ufromfpf128
+    libc.src.math.ufromfpxf128
   )
 endif()
 
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index d337d060fb5dd9..fa604faaec2ff0 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -181,6 +181,22 @@ Basic Operations
 +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
 | frexpf128    | |check| | |check| |         | |check| |         |         |         |         |         |         |         |         |
 +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfp       | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpf      | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpl      | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpf128   | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpx      | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpxf     | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpxl     | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| fromfpxf128  | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
 | ilogb        | |check| | |check| | |check| | |check| | |check| |         |         | |check| | |check| | |check| |         |         |
 +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
 | ilogbf       | |check| | |check| | |check| | |check| | |check| |         |         | |check| | |check| | |check| |         |         |
@@ -339,6 +355,22 @@ Basic Operations
 +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
 | truncf128    | |check| | |check| |         | |check| |         |         |         |         |         |         |         |         |
 +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfp      | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpf     | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpl     | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpf128  | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpx     | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpxf    | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpxl    | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
+| ufromfpxf128 | |check| |         |         |         |         |         |         |         |         |         |         |         |
++--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
 
 
 Higher Math Functions
diff --git a/libc/include/llvm-libc-macros/math-macros.h b/libc/include/llvm-libc-macros/math-macros.h
index db8a4ea65bd69a..0d89f020ebb8e6 100644
--- a/libc/include/llvm-libc-macros/math-macros.h
+++ b/libc/include/llvm-libc-macros/math-macros.h
@@ -17,6 +17,12 @@
 #define FP_SUBNORMAL 3
 #define FP_NORMAL 4
 
+#define FP_INT_UPWARD 0
+#define FP_INT_DOWNWARD 1
+#define FP_INT_TOWARDZERO 2
+#define FP_INT_TONEARESTFROMZERO 3
+#define FP_INT_TONEAREST 4
+
 #define MATH_ERRNO 1
 #define MATH_ERREXCEPT 2
 
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 84d28cc3350304..5f425ba1120a23 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -352,6 +352,12 @@ def StdC : StandardSpec<"stdc"> {
           Macro<"INFINITY">,
           Macro<"NAN">,
 
+          Macro<"FP_INT_UPWARD">,
+          Macro<"FP_INT_DOWNWARD">,
+          Macro<"FP_INT_TOWARDZERO">,
+          Macro<"FP_INT_TONEARESTFROMZERO">,
+          Macro<"FP_INT_TONEAREST">,
+
           Macro<"FP_ILOGB0">,
           Macro<"FP_ILOGBNAN">,
 
@@ -414,6 +420,26 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"frexpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntPtr>]>,
           GuardedFunctionSpec<"frexpf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<IntPtr>], "LIBC_TYPES_HAS_FLOAT128">,
 
+          FunctionSpec<"fromfp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"fromfpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"fromfpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"fromfpf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+
+          FunctionSpec<"fromfpx", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"fromfpxf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"fromfpxl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"fromfpxf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+
+          FunctionSpec<"ufromfp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"ufromfpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"ufromfpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"ufromfpf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+
+          FunctionSpec<"ufromfpx", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"ufromfpxf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"ufromfpxl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"ufromfpxf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
+
           FunctionSpec<"hypot", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
           FunctionSpec<"hypotf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
 
diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h
index e890e38ba4ae7d..cef612f9263529 100644
--- a/libc/src/__support/FPUtil/NearestIntegerOperations.h
+++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h
@@ -141,7 +141,7 @@ LIBC_INLINE T round(T x) {
 }
 
 template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE T round_using_current_rounding_mode(T x) {
+LIBC_INLINE constexpr T round_using_specific_rounding_mode(T x, int rnd) {
   using StorageType = typename FPBits<T>::StorageType;
   FPBits<T> bits(x);
 
@@ -151,7 +151,6 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
 
   bool is_neg = bits.is_neg();
   int exponent = bits.get_exponent();
-  int rounding_mode = quick_get_round();
 
   // If the exponent is greater than the most negative mantissa
   // exponent, then x is already an integer.
@@ -159,20 +158,23 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
     return x;
 
   if (exponent <= -1) {
-    switch (rounding_mode) {
-    case FE_DOWNWARD:
+    switch (rnd) {
+    case FP_INT_DOWNWARD:
       return is_neg ? T(-1.0) : T(0.0);
-    case FE_UPWARD:
+    case FP_INT_UPWARD:
       return is_neg ? T(-0.0) : T(1.0);
-    case FE_TOWARDZERO:
+    case FP_INT_TOWARDZERO:
       return is_neg ? T(-0.0) : T(0.0);
-    case FE_TONEAREST:
+    case FP_INT_TONEARESTFROMZERO:
+      if (exponent < -1)
+        return is_neg ? T(-0.0) : T(0.0); // abs(x) < 0.5
+      return is_neg ? T(-1.0) : T(1.0);   // abs(x) >= 0.5
+    case FP_INT_TONEAREST:
+    default:
       if (exponent <= -2 || bits.get_mantissa() == 0)
         return is_neg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
       else
         return is_neg ? T(-1.0) : T(1.0); // abs(x) > 0.5
-    default:
-      __builtin_unreachable();
     }
   }
 
@@ -194,14 +196,19 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
   StorageType trunc_is_odd =
       new_bits.get_mantissa() & (StorageType(1) << trim_size);
 
-  switch (rounding_mode) {
-  case FE_DOWNWARD:
+  switch (rnd) {
+  case FP_INT_DOWNWARD:
     return is_neg ? trunc_value - T(1.0) : trunc_value;
-  case FE_UPWARD:
+  case FP_INT_UPWARD:
     return is_neg ? trunc_value : trunc_value + T(1.0);
-  case FE_TOWARDZERO:
+  case FP_INT_TOWARDZERO:
     return trunc_value;
-  case FE_TONEAREST:
+  case FP_INT_TONEARESTFROMZERO:
+    if (trim_value >= half_value)
+      return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
+    return trunc_value;
+  case FP_INT_TONEAREST:
+  default:
     if (trim_value > half_value) {
       return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
     } else if (trim_value == half_value) {
@@ -214,11 +221,66 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
     } else {
       return trunc_value;
     }
+  }
+}
+
+template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE T round_using_current_rounding_mode(T x) {
+  int rounding_mode = quick_get_round();
+
+  switch (rounding_mode) {
+  case FE_DOWNWARD:
+    return round_using_specific_rounding_mode(x, FP_INT_DOWNWARD);
+  case FE_UPWARD:
+    return round_using_specific_rounding_mode(x, FP_INT_UPWARD);
+  case FE_TOWARDZERO:
+    return round_using_specific_rounding_mode(x, FP_INT_TOWARDZERO);
+  case FE_TONEAREST:
+    return round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
   default:
     __builtin_unreachable();
   }
 }
 
+template <bool IsSigned, typename T,
+          cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE constexpr T fromfp(T x, int rnd, unsigned int width) {
+  if (width == 0U)
+    return FPBits<T>::quiet_nan().get_val();
+
+  T rounded_value = round_using_specific_rounding_mode(x, rnd);
+
+  if constexpr (IsSigned) {
+    // T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
+    if (width - 1 > FPBits<T>::EXP_BIAS)
+      return rounded_value;
+    if (rounded_value < -T(1U << (width - 1U)))
+      return FPBits<T>::quiet_nan().get_val();
+    if (rounded_value > T((1U << (width - 1U)) - 1U))
+      return FPBits<T>::quiet_nan().get_val();
+    return rounded_value;
+  }
+
+  if (rounded_value < T(0.0))
+    return FPBits<T>::quiet_nan().get_val();
+  // T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
+  if (width <= FPBits<T>::EXP_BIAS && rounded_value > T(1U << width) - 1U)
+    return FPBits<T>::quiet_nan().get_val();
+  return rounded_value;
+}
+
+template <bool IsSigned, typename T,
+          cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
+LIBC_INLINE constexpr T fromfpx(T x, int rnd, unsigned int width) {
+  T rounded_value = fromfp<IsSigned>(x, rnd, width);
+  FPBits<T> bits(rounded_value);
+
+  if (!bits.is_nan() && rounded_value != x)
+    raise_except_if_required(FE_INEXACT);
+
+  return rounded_value;
+}
+
 namespace internal {
 
 template <typename F, typename I,
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 5e2e6e699d0e0c..2f1d65780013f8 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -127,6 +127,16 @@ add_math_entrypoint_object(frexpf)
 add_math_entrypoint_object(frexpl)
 add_math_entrypoint_object(frexpf128)
 
+add_math_entrypoint_object(fromfp)
+add_math_entrypoint_object(fromfpf)
+add_math_entrypoint_object(fromfpl)
+add_math_entrypoint_object(fromfpf128)
+
+add_math_entrypoint_object(fromfpx)
+add_math_entrypoint_object(fromfpxf)
+add_math_entrypoint_object(fromfpxl)
+add_math_entrypoint_object(fromfpxf128)
+
 add_math_entrypoint_object(hypot)
 add_math_entrypoint_object(hypotf)
 
@@ -267,3 +277,13 @@ add_math_entrypoint_object(trunc)
 add_math_entrypoint_object(truncf)
 add_math_entrypoint_object(truncl)
 add_math_entrypoint_object(truncf128)
+
+add_math_entrypoint_object(ufromfp)
+add_math_entrypoint_object(ufromfpf)
+add_math_entrypoint_object(ufromfpl)
+add_math_entrypoint_object(ufromfpf128)
+
+add_math_entrypoint_object(ufromfpx)
+add_math_entrypoint_object(ufromfpxf)
+add_math_entrypoint_object(ufromfpxl)
+add_math_entrypoint_object(ufromfpxf128)
diff --git a/libc/src/math/fromfp.h b/libc/src/math/fromfp.h
new file mode 100644
index 00000000000000..d3de2dd3460832
--- /dev/null
+++ b/libc/src/math/fromfp.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for fromfp ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FROMFP_H
+#define LLVM_LIBC_SRC_MATH_FROMFP_H
+
+namespace LIBC_NAMESPACE {
+
+double fromfp(double x, int rnd, unsigned int width);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FROMFP_H
diff --git a/libc/src/math/fromfpf.h b/libc/src/math/fromfpf.h
new file mode 100644
index 00000000000000..11d432148d0189
--- /dev/null
+++ b/libc/src/math/fromfpf.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for fromfpf -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FROMFPF_H
+#define LLVM_LIBC_SRC_MATH_FROMFPF_H
+
+namespace LIBC_NAMESPACE {
+
+float fromfpf(float x, int rnd, unsigned int width);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FROMFPF_H
diff --git a/libc/src/math/fromfpf128.h b/libc/src/math/fromfpf128.h
new file mode 100644
index 00000000000000..5f85fde570a0fb
--- /dev/null
+++ b/libc/src/math/fromfpf128.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for fromfpf128 --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FROMFPF128_H
+#define LLVM_LIBC_SRC_MATH_FROMFPF128_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float128 fromfpf128(float128 x, int rnd, unsigned int width);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FROMFPF128_H
diff --git a/libc/src/math/fromfpl.h b/libc/src/math/fromfpl.h
new file mode 100644
index 00000000000000..dd8e1eebdea994
--- /dev/null
+++ b/libc/src/math/fromfpl.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for fromfpl -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_MATH_FROMFPL_H
+#define LLVM_LIBC_SRC_MATH_FROMFPL_H
+
+namespace LIBC_NAMESPACE {
+
+long double fromfpl(long double x, int rnd, unsigned int width);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FROMFPL_H
diff --git a/libc/src/math/fromfpx.h b/libc/src/math/fromfpx.h
new file mode 100644
index 0000000000...
[truncated]

HDRS
FromfpTest.h
DEPENDS
libc.src.math.fromfp
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my previous PR for nextup and nextdown I had added more dependencies: https://github.com/llvm/llvm-project/pull/85431/files#diff-2269fc16d8717f30b774875846f93f54879dae7515bdfd3dd5d5645fd7413aa7R1626-R1628.

Now that I think about it again, I assume that depending on libc.src.math.<func> is enough to also depend on the header and dependencies declared in the add_entrypoint_object call for the function in libc/src/math/generic/CMakeLists.txt.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but include-what-you-use is always better, instead of completely relying on transitive dependence. So if your test directly calls something in those targets, it's always better to directly include them in our DEPENDS list.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but the nextup and nextdown tests only directly use libc.src.math.{nextup,nextdown} and test/UnitTest/{FPMatcher.h,Test.h}, and add_fp_unittest already takes care of the latter.

EXPECT_FP_EQ(aNaN, func(T(-1234.96), FP_INT_DOWNWARD, 11U));
}

void testFractionsTowardZeroWithinRange(FromfpxFunc func) {
Copy link
Member Author

@overmighty overmighty Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting for the tests that use EXPECT_FP_EQ_WITH_EXCEPTION isn't great with lines of different lengths triggering different wrap-arounds, but I'm not sure if it's a problem.

Note that FromfpxTest.h is pretty much a copy-paste of FromfpTest.h with testFractions*WithinRange tests changed to use EXPECT_FP_EQ_WITH_EXCEPTION. Same for UfromfpxTest.h vs UfromfpTest.h. I'm not sure if something should be done about this either.

@lntue lntue self-requested a review March 20, 2024 22:08
@overmighty
Copy link
Member Author

I added tests for the fallback to FP_INT_TONEAREST when the value of the rnd argument doesn't match the value of any math rounding direction macro.


Unknown Math Rounding Direction
-------------------------------
The C standard states that if the value of the ``rnd`` argument of the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: C23

libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.nearest_integer
COMPILE_OPTIONS
-O3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: alignment

@overmighty overmighty force-pushed the libc-math-fromfp-fromfpx-ufromfp-ufromfpx branch from 9616f21 to ac71b02 Compare March 22, 2024 20:43
@overmighty
Copy link
Member Author

Had to rebase as Bazel builds were broken before #86298.

Copy link

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link

✅ With the latest revision this PR passed the Python code formatter.

@@ -141,7 +141,7 @@ LIBC_INLINE T round(T x) {
}

template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T round_using_current_rounding_mode(T x) {
LIBC_INLINE constexpr T round_using_specific_rounding_mode(T x, int rnd) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are here, would you mind updating the enable_if to be on the returning type instead:

template <typename T>
LIBC_INLINE constexpr typename cpp::enable_if_t<..., T> rounding_using_specific_rounding_mode() { ... }

Same for the other 2 functions below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLion Nova warns about the typename keyword before cpp::enable_if_t being redundant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove typename before cpp::enable_if_t if it's not needed.

@lntue
Copy link
Contributor

lntue commented Mar 25, 2024

Thanks for adding these functions! I'll merge the patch in the morning when I can watch the bots.

LIBC_INLINE T round_using_current_rounding_mode(T x) {
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
round_using_specific_rounding_mode(T x, int rnd) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this function should have been made static or put in a namespace.

@overmighty
Copy link
Member Author

You're welcome.

By the way, roundeven could be implemented similarly to fputil::round and the branches for FP_INT_TONEAREST in fputil::round_using_specific_rounding_mode. I can work on this later if you want.

@lntue lntue merged commit b282259 into llvm:main Mar 25, 2024
@overmighty
Copy link
Member Author

By the way, roundeven could be implemented similarly to fputil::round and the branches for FP_INT_TONEAREST in fputil::round_using_specific_rounding_mode. I can work on this later if you want.

Addressed by #87678.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bazel "Peripheral" support tier build system: utils/bazel libc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[libc][math][c23] Implement C23 math functions fromfp, fromfpx, ufromfp, ufromfpx
3 participants