[libc-commits] [libc] [libc][stdfix] Implement fxdivi functions (rdivi) (PR #154914)

Shreeyash Pandey via libc-commits libc-commits at lists.llvm.org
Fri Aug 22 02:07:09 PDT 2025


https://github.com/bojle created https://github.com/llvm/llvm-project/pull/154914

This PR includes only one of the fxdivi functions (rdivi). It uses a polynomial function for initial approximation followed by 4 newton-raphson iterations to calculate the reciprocal and finally multiplies the numerator with it to get the result. 

>From 7c517bf9970f3de49a0a5a261f87701daa584acc Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Fri, 22 Aug 2025 14:16:57 +0530
Subject: [PATCH] [libc][stdfix] Implement fxdivi functions

Signed-off-by: Shreeyash Pandey <shreeyash335 at gmail.com>
---
 libc/config/linux/riscv/entrypoints.txt  |  1 +
 libc/config/linux/x86_64/entrypoints.txt |  1 +
 libc/include/stdfix.yaml                 |  8 +++++
 libc/src/__support/fixed_point/fx_bits.h | 41 ++++++++++++++++++++++++
 libc/src/stdfix/CMakeLists.txt           | 14 ++++++++
 libc/test/src/stdfix/CMakeLists.txt      | 16 +++++++++
 6 files changed, 81 insertions(+)

diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 1a03683d72e61..b783dd4b04c74 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -986,6 +986,7 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.idivulr
     libc.src.stdfix.idivuk
     libc.src.stdfix.idivulk
+    libc.src.stdfix.rdivi
   )
 endif()
 
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5590f1a15ac57..f6beccc7229dd 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1019,6 +1019,7 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.idivulr
     libc.src.stdfix.idivuk
     libc.src.stdfix.idivulk
+    libc.src.stdfix.rdivi
   )
 endif()
 
diff --git a/libc/include/stdfix.yaml b/libc/include/stdfix.yaml
index 5b385124eb63d..451330c3478d2 100644
--- a/libc/include/stdfix.yaml
+++ b/libc/include/stdfix.yaml
@@ -544,3 +544,11 @@ functions:
     arguments:
       - type: unsigned long accum
     guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: rdivi
+    standards:
+      - stdc_ext
+    return_type: fract
+    arguments:
+      - type: int
+      - type: int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index 00c6119b4f353..13eecba981664 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -224,6 +224,47 @@ idiv(T x, T y) {
   return static_cast<XType>(result);
 }
 
+inline long accum nrstep(long accum d, long accum x0) {
+  auto v = x0 * (2 - (d * x0));
+  return v;
+}
+
+/* Divide the two integers and return a fixed_point value
+ *
+ * For reference, see:
+ * https://en.wikipedia.org/wiki/Division_algorithm#Newton%E2%80%93Raphson_division
+ * https://stackoverflow.com/a/9231996
+ */
+template <typename XType> LIBC_INLINE constexpr XType divi(int n, int d) {
+  // If the value of the second operand of the / operator is zero, the
+  // behavior is undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16
+  LIBC_CRASH_ON_VALUE(d, 0);
+
+  unsigned int nv = static_cast<unsigned int>(n);
+  unsigned int dv = static_cast<unsigned int>(d);
+  unsigned int clz = cpp::countl_zero<unsigned int>(dv) - 1;
+  unsigned long int scaled_val = dv << clz;
+  /* Scale denominator to be in the range of [0.5,1] */
+  FXBits<long accum> d_scaled{scaled_val};
+  unsigned long int scaled_val_n = nv << clz;
+  /* Scale the numerator as much as the denominator to maintain correctness of
+   * the original equation
+   */
+  FXBits<long accum> n_scaled{scaled_val_n};
+  long accum n_scaled_val = n_scaled.get_val();
+  long accum d_scaled_val = d_scaled.get_val();
+  /* x0 = (48/17) - (32/17) * d_n */
+  long accum a = 2.8235lk; /* 48/17 */
+  long accum b = 1.8823lk; /* 32/17 */
+  long accum initial_approx = a - (b * d_scaled_val);
+  long accum val = nrstep(d_scaled_val, initial_approx);
+  val = nrstep(d_scaled_val, val);
+  val = nrstep(d_scaled_val, val);
+  val = nrstep(d_scaled_val, val);
+  long accum res = n_scaled_val * val;
+  return static_cast<XType>(res);
+}
+
 } // namespace fixed_point
 } // namespace LIBC_NAMESPACE_DECL
 
diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
index 843111e3f80b1..3cbabd17ad34c 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -89,6 +89,20 @@ foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
   )
 endforeach()
 
+foreach(suffix IN ITEMS r)
+  add_entrypoint_object(
+    ${suffix}divi
+    HDRS
+      ${suffix}divi.h
+    SRCS
+      ${suffix}divi.cpp
+    COMPILE_OPTIONS
+      ${libc_opt_high_flag}
+    DEPENDS
+      libc.src.__support.fixed_point.fx_bits
+  )
+endforeach()
+
 add_entrypoint_object(
   uhksqrtus
   HDRS
diff --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt
index e2b4bc1805f7c..741522276feaa 100644
--- a/libc/test/src/stdfix/CMakeLists.txt
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -120,6 +120,22 @@ foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
   )
 endforeach()
 
+foreach(suffix IN ITEMS r)
+  add_libc_test(
+    ${suffix}divi_test
+    SUITE
+      libc-stdfix-tests
+    HDRS
+      DivITest.h
+    SRCS
+      ${suffix}divi_test.cpp
+    DEPENDS
+      libc.src.stdfix.${suffix}divi
+      libc.src.__support.fixed_point.fx_bits
+      libc.hdr.signal_macros
+  )
+endforeach()
+
 add_libc_test(
   uhksqrtus_test
   SUITE



More information about the libc-commits mailing list