[libc-commits] [libc] [libc][stdfix] Implement fixed point fxdivi functions in llvm-libc (PR #210020)

via libc-commits libc-commits at lists.llvm.org
Thu Jul 16 02:56:37 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: sohail (sohail103)

<details>
<summary>Changes</summary>

This PR implements the following 8 functions along with unit tests.

```cpp
fract rdivi(int, int);
long fract lrdivi(long int, long int);
accum kdivi(int, int);
long accum lkdivi(long int, long int);
unsigned fract urdivi(unsigned int, unsigned int);
unsigned long fract ulrdivi(unsigned long int, unsigned long int);
unsigned accum ukdivi(unsigned int, unsigned int);
unsigned long accum ulkdivi(unsigned long int, unsigned long int);
```

Fixes #<!-- -->129126.

---

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


35 Files Affected:

- (modified) libc/config/baremetal/arm/entrypoints.txt (+8) 
- (modified) libc/config/baremetal/riscv/entrypoints.txt (+8) 
- (modified) libc/config/linux/riscv/entrypoints.txt (+7) 
- (modified) libc/config/linux/x86_64/entrypoints.txt (+7) 
- (modified) libc/docs/headers/stdfix.rst (+1-1) 
- (modified) libc/include/stdfix.yaml (+56) 
- (modified) libc/src/__support/fixed_point/fx_bits.h (+111-89) 
- (modified) libc/src/stdfix/CMakeLists.txt (+1-1) 
- (added) libc/src/stdfix/kdivi.cpp (+19) 
- (added) libc/src/stdfix/kdivi.h (+21) 
- (added) libc/src/stdfix/lkdivi.cpp (+19) 
- (added) libc/src/stdfix/lkdivi.h (+21) 
- (added) libc/src/stdfix/lrdivi.cpp (+19) 
- (added) libc/src/stdfix/lrdivi.h (+21) 
- (modified) libc/src/stdfix/rdivi.cpp (+5-7) 
- (modified) libc/src/stdfix/rdivi.h (+1-1) 
- (added) libc/src/stdfix/ukdivi.cpp (+19) 
- (added) libc/src/stdfix/ukdivi.h (+21) 
- (added) libc/src/stdfix/ulkdivi.cpp (+20) 
- (added) libc/src/stdfix/ulkdivi.h (+21) 
- (added) libc/src/stdfix/ulrdivi.cpp (+20) 
- (added) libc/src/stdfix/ulrdivi.h (+21) 
- (added) libc/src/stdfix/urdivi.cpp (+19) 
- (added) libc/src/stdfix/urdivi.h (+21) 
- (modified) libc/test/src/stdfix/CMakeLists.txt (+2-2) 
- (removed) libc/test/src/stdfix/DivITest.h (-74) 
- (added) libc/test/src/stdfix/FxDiviTest.h (+189) 
- (added) libc/test/src/stdfix/kdivi_test.cpp (+14) 
- (added) libc/test/src/stdfix/lkdivi_test.cpp (+14) 
- (added) libc/test/src/stdfix/lrdivi_test.cpp (+14) 
- (modified) libc/test/src/stdfix/rdivi_test.cpp (+3-3) 
- (added) libc/test/src/stdfix/ukdivi_test.cpp (+14) 
- (added) libc/test/src/stdfix/ulkdivi_test.cpp (+15) 
- (added) libc/test/src/stdfix/ulrdivi_test.cpp (+15) 
- (added) libc/test/src/stdfix/urdivi_test.cpp (+14) 


``````````diff
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index c7632b9cca225..21d26a77bdbfa 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -982,6 +982,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.diviulr
     libc.src.stdfix.diviuk
     libc.src.stdfix.diviulk
+    libc.src.stdfix.rdivi
+    libc.src.stdfix.lrdivi
+    libc.src.stdfix.kdivi
+    libc.src.stdfix.lkdivi
+    libc.src.stdfix.urdivi
+    libc.src.stdfix.ulrdivi
+    libc.src.stdfix.ukdivi
+    libc.src.stdfix.ulkdivi
   )
 endif()
 
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 5918ac2bc4282..8c8d94a3ff3d1 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -979,6 +979,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.diviulr
     libc.src.stdfix.diviuk
     libc.src.stdfix.diviulk
+    libc.src.stdfix.rdivi
+    libc.src.stdfix.lrdivi
+    libc.src.stdfix.kdivi
+    libc.src.stdfix.lkdivi
+    libc.src.stdfix.urdivi
+    libc.src.stdfix.ulrdivi
+    libc.src.stdfix.ukdivi
+    libc.src.stdfix.ulkdivi
   )
 endif()
 
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index c9eb605423bbc..e05b3feaf82b2 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1188,6 +1188,13 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.idivuk
     libc.src.stdfix.idivulk
     libc.src.stdfix.rdivi
+    libc.src.stdfix.lrdivi
+    libc.src.stdfix.kdivi
+    libc.src.stdfix.lkdivi
+    libc.src.stdfix.urdivi
+    libc.src.stdfix.ulrdivi
+    libc.src.stdfix.ukdivi
+    libc.src.stdfix.ulkdivi
     libc.src.stdfix.divir
     libc.src.stdfix.divilr
     libc.src.stdfix.divik
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index d5f9c29836939..e23ea0aacba64 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1193,6 +1193,13 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.idivuk
     libc.src.stdfix.idivulk
     libc.src.stdfix.rdivi
+    libc.src.stdfix.lrdivi
+    libc.src.stdfix.kdivi
+    libc.src.stdfix.lkdivi
+    libc.src.stdfix.urdivi
+    libc.src.stdfix.ulrdivi
+    libc.src.stdfix.ukdivi
+    libc.src.stdfix.ulkdivi
     libc.src.stdfix.divir
     libc.src.stdfix.divilr
     libc.src.stdfix.divik
diff --git a/libc/docs/headers/stdfix.rst b/libc/docs/headers/stdfix.rst
index 91dad81c595b0..ac1419be7a066 100644
--- a/libc/docs/headers/stdfix.rst
+++ b/libc/docs/headers/stdfix.rst
@@ -79,7 +79,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard.
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
 | muli          |                |             |               |            |                |             |                |             |               |            |                |             |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
-| \*divi        |                |             |               | |check|    |                |             |                |             |               |            |                |             |
+| \*divi        |                |             | |check|       | |check|    | |check|        | |check|     |                |             | |check|       | |check|    | |check|        | |check|     |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
 | round         | |check|        | |check|     | |check|       | |check|    | |check|        | |check|     | |check|        | |check|     | |check|       | |check|    | |check|        | |check|     |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
diff --git a/libc/include/stdfix.yaml b/libc/include/stdfix.yaml
index f91e4ea620e3e..739805ea2a39a 100644
--- a/libc/include/stdfix.yaml
+++ b/libc/include/stdfix.yaml
@@ -565,6 +565,62 @@ functions:
       - type: int
       - type: int
     guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: lrdivi
+    standards:
+      - stdc_ext
+    return_type: long fract
+    arguments:
+      - type: long int
+      - type: long int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: kdivi
+    standards:
+      - stdc_ext
+    return_type: accum
+    arguments:
+      - type: int
+      - type: int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: lkdivi
+    standards:
+      - stdc_ext
+    return_type: long accum
+    arguments:
+      - type: long int
+      - type: long int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: urdivi
+    standards:
+      - stdc_ext
+    return_type: unsigned fract
+    arguments:
+      - type: unsigned int
+      - type: unsigned int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: ulrdivi
+    standards:
+      - stdc_ext
+    return_type: unsigned long fract
+    arguments:
+      - type: unsigned long int
+      - type: unsigned long int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: ukdivi
+    standards:
+      - stdc_ext
+    return_type: unsigned accum
+    arguments:
+      - type: unsigned int
+      - type: unsigned int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: ulkdivi
+    standards:
+      - stdc_ext
+    return_type: unsigned long accum
+    arguments:
+      - type: unsigned long int
+      - type: unsigned long int
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
   - name: divir
     standards:
       - stdc_ext
diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index 256bb3a967fbf..6b800372d316b 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -227,111 +227,133 @@ idiv(T x, T y) {
   return static_cast<XType>(result);
 }
 
-LIBC_INLINE long accum nrstep(long accum d, long accum x0) {
-  auto v = x0 * (2.lk - (d * x0));
-  return v;
-}
-
-// Divide the two integers and return a fixed_point value
-//
+// Divide 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
+// https://stackoverflow.com/a/9231996.
+template <typename FXType, typename IntType>
+LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<FXType>, FXType>
+fxdivi(IntType n, IntType d) {
+  using OutRep = FXRep<FXType>;
+  static_assert(cpp::is_signed_v<IntType> == (OutRep::SIGN_LEN > 0),
+                "IntType and FXType must have matching signedness");
+  constexpr bool IS_SIGNED = OutRep::SIGN_LEN > 0;
+  using UIntType = cpp::make_unsigned_t<IntType>;
 
-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
+  // behavior is undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16.
   LIBC_CRASH_ON_VALUE(d, 0);
-
-  if (LIBC_UNLIKELY(n == 0)) {
-    return FXRep<XType>::ZERO();
+  if (LIBC_UNLIKELY(n == 0))
+    return OutRep::ZERO();
+
+  // n == d and d != 0 means the quotient is 1. The general NR path can't
+  // guarantee landing on 1 exactly so special case for this.
+  if (LIBC_UNLIKELY(n == d)) {
+    if constexpr (OutRep::INTEGRAL_LEN > 0)
+      return static_cast<FXType>(1);
+    else
+      return OutRep::MAX();
   }
-  auto is_power_of_two = [](int n) { return (n > 0) && ((n & (n - 1)) == 0); };
-  long accum max_val = static_cast<long accum>(FXRep<XType>::MAX());
-  long accum min_val = static_cast<long accum>(FXRep<XType>::MIN());
-
-  if (is_power_of_two(cpp::abs(d))) {
-    int k = cpp::countr_zero<uint32_t>(static_cast<uint32_t>(cpp::abs(d)));
-    constexpr int F = FXRep<XType>::FRACTION_LEN;
-    int64_t scaled_n = static_cast<int64_t>(n) << F;
-    int64_t res64 = scaled_n >> k;
-    constexpr int TOTAL_BITS = sizeof(XType) * 8;
-    const int64_t max_limit = (1LL << (TOTAL_BITS - 1)) - 1;
-    const int64_t min_limit = -(1LL << (TOTAL_BITS - 1));
-    if (res64 > max_limit) {
-      return FXRep<XType>::MAX();
-    } else if (res64 < min_limit) {
-      return FXRep<XType>::MIN();
-    }
-    long accum res_accum =
-        static_cast<long accum>(res64) / static_cast<long accum>(1 << F);
-    res_accum = (d < 0) ? static_cast<long accum>(-1) * res_accum : res_accum;
-    if (res_accum > max_val) {
-      return FXRep<XType>::MAX();
-    } else if (res_accum < min_val) {
-      return FXRep<XType>::MIN();
-    }
-    return static_cast<XType>(res_accum);
+
+  // Intermediate arithmetic is done in a wide fixed-point type.
+  using WideFXType =
+      cpp::conditional_t<IS_SIGNED, long accum, unsigned long accum>;
+  using WideRep = FXRep<WideFXType>;
+  using WideStorage = typename WideRep::StorageType;
+  constexpr int F = OutRep::FRACTION_LEN;
+  constexpr int WF = WideRep::FRACTION_LEN;
+
+  // Split each operand into a sign and a magnitude.
+  bool result_is_negative = false;
+  UIntType n_mag, d_mag;
+  if constexpr (IS_SIGNED) {
+    result_is_negative = (n < 0) != (d < 0);
+    n_mag = (n < 0) ? -static_cast<UIntType>(n) : static_cast<UIntType>(n);
+    d_mag = (d < 0) ? -static_cast<UIntType>(d) : static_cast<UIntType>(d);
+  } else {
+    n_mag = n;
+    d_mag = d;
   }
 
-  bool result_is_negative = ((n < 0) != (d < 0));
-  int64_t n64 = static_cast<int64_t>(n);
-  int64_t d64 = static_cast<int64_t>(d);
+  WideFXType res;
 
-  uint64_t nv = static_cast<uint64_t>(n64 < 0 ? -n64 : n64);
-  uint64_t dv = static_cast<uint64_t>(d64 < 0 ? -d64 : d64);
+  if ((d_mag & (d_mag - 1)) == 0) {
+    // d is a power of 2. n/d is an exact right shift.
+    int log2_d = cpp::countr_zero(d_mag);
 
-  if (d == INT_MIN) {
-    nv <<= 1;
-    dv >>= 1;
-  }
+    constexpr int INTERMEDIATE_BITS =
+        cpp::numeric_limits<UIntType>::digits + WF;
+    using WideIntType =
+        cpp::conditional_t<(INTERMEDIATE_BITS <= 64), uint64_t, UInt128>;
+    WideIntType scaled_n = (static_cast<WideIntType>(n_mag) << WF) >> log2_d;
 
-  uint32_t clz = cpp::countl_zero<uint32_t>(static_cast<uint32_t>(dv)) - 1;
-  uint64_t scaled_val = dv << clz;
-  // Scale denominator to be in the range of [0.5,1]
-  FXBits<long accum> d_scaled{scaled_val};
-  uint64_t 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 = 0x2.d89d89d8p0lk; // 48/17 = 2.8235294...
-  long accum b = 0x1.e1e1e1e1p0lk; // 32/17 = 1.8823529...
-  // Error of the initial approximation, as derived
-  // from the wikipedia article is
-  //  E0 = 1/17 = 0.059 (5.9%)
-  long accum initial_approx = a - (b * d_scaled_val);
-  // Since, 0.5 <= d_scaled_val <= 1.0, 0.9412 <= initial_approx <= 1.88235
-  LIBC_ASSERT((initial_approx >= 0x0.78793dd9p0lk) &&
-              (initial_approx <= 0x1.f0f0d845p0lk));
-  // Each newton-raphson iteration will square the error, due
-  // to quadratic convergence. So,
-  // E1 = (0.059)^2 = 0.0034
-  long accum val = nrstep(d_scaled_val, initial_approx);
-  if constexpr (FXRep<XType>::FRACTION_LEN > 8) {
-    // E2 = 0.0000121
-    val = nrstep(d_scaled_val, val);
-    if constexpr (FXRep<XType>::FRACTION_LEN > 16) {
-      // E3 = 1.468e−10
-      val = nrstep(d_scaled_val, val);
-    }
+    constexpr int WIDE_STORAGE_BITS = cpp::numeric_limits<WideStorage>::digits;
+    if (LIBC_UNLIKELY((static_cast<UInt128>(scaled_n) >> WIDE_STORAGE_BITS) !=
+                      0))
+      return result_is_negative ? OutRep::MIN() : OutRep::MAX();
+
+    res = FXBits<WideFXType>(static_cast<WideStorage>(scaled_n)).get_val();
+  } else {
+    // General case: Approximate 1/d, then multiply by n.
+
+    // Normalize d_mag into a WF fraction value in [0.5, 1) and apply the same
+    // shift to n_mag so that n_scaled/d_scaled = n/d.
+    constexpr int W = cpp::numeric_limits<UIntType>::digits;
+    int d_msb = (W - 1) - cpp::countl_zero(d_mag);
+    int norm_shift = (WF - 1) - d_msb;
+
+    auto scale = [norm_shift](UIntType v) -> WideFXType {
+      WideStorage wide_v = static_cast<WideStorage>(v);
+      WideStorage shifted =
+          norm_shift >= 0 ? (wide_v << norm_shift) : (wide_v >> -norm_shift);
+      return FXBits<WideFXType>(shifted).get_val();
+    };
+
+    WideFXType d_scaled = scale(d_mag);
+    WideFXType n_scaled = scale(n_mag);
+
+    // Initial approximation of 1/d_scaled: x0 = 48/17 - (32/17) * d_scaled.
+    // d_scaled is in [0.5, 1) so x0 is in [0.941, 1.882] with a worst-case
+    // relative error bounded by 1/17 (~5.88%).
+    WideFXType a = static_cast<WideFXType>(0x2.d89d89d8p0lk); // 48/17
+    WideFXType b = static_cast<WideFXType>(0x1.e1e1e1e1p0lk); // 32/17
+    WideFXType initial_approx = a - b * d_scaled;
+
+    auto nrstep = [](WideFXType d_, WideFXType x0) {
+      return x0 * (static_cast<WideFXType>(2) - d_ * x0);
+    };
+
+    // Each iteration squares the relative error (quadratic convergence).
+    WideFXType recip = nrstep(d_scaled, initial_approx); // E1 <= 0.346%
+
+    if constexpr (F >= 7)
+      recip = nrstep(d_scaled, recip); // E2 <= 1.197e-5
+
+    if constexpr (F >= 15)
+      recip = nrstep(d_scaled, recip); // E3 <= 1.434e-10
+
+    if constexpr (F >= 31)
+      recip = nrstep(d_scaled, recip); // E4 <= 2.055e-20
+
+    res = n_scaled * recip;
   }
-  long accum res = n_scaled_val * val;
 
-  if (result_is_negative) {
-    res *= static_cast<long accum>(-1);
+  if constexpr (IS_SIGNED) {
+    if (result_is_negative)
+      res = -res;
   }
 
-  // Per clause 7.18a.6.1, saturate values on overflow
-  if (res > max_val) {
-    return FXRep<XType>::MAX();
-  } else if (res < min_val) {
-    return FXRep<XType>::MIN();
-  } else {
-    return static_cast<XType>(res);
+  // According to clause 7.18a.6.1, saturate the result on overflow.
+  WideFXType max_val = static_cast<WideFXType>(OutRep::MAX());
+  if (res > max_val)
+    return OutRep::MAX();
+  if constexpr (IS_SIGNED) {
+    WideFXType min_val = static_cast<WideFXType>(OutRep::MIN());
+    if (res < min_val)
+      return OutRep::MIN();
   }
+
+  return static_cast<FXType>(res);
 }
 
 // Divide an integer operand by a fixed-point operand and return the
diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
index b7121407e0307..71ad93c321e69 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -88,7 +88,7 @@ foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
   )
 endforeach()
 
-foreach(suffix IN ITEMS r)
+foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
   add_entrypoint_object(
     ${suffix}divi
     HDRS
diff --git a/libc/src/stdfix/kdivi.cpp b/libc/src/stdfix/kdivi.cpp
new file mode 100644
index 0000000000000..0441c495ffada
--- /dev/null
+++ b/libc/src/stdfix/kdivi.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of kdivi function ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "kdivi.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(accum, kdivi, (int n, int d)) {
+  return fixed_point::fxdivi<accum, int>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/kdivi.h b/libc/src/stdfix/kdivi.h
new file mode 100644
index 0000000000000..b570b5c213fd6
--- /dev/null
+++ b/libc/src/stdfix/kdivi.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for kdivi -------------------------*- 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_STDFIX_KDIVI_H
+#define LLVM_LIBC_SRC_STDFIX_KDIVI_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+accum kdivi(int n, int d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_KDIVI_H
diff --git a/libc/src/stdfix/lkdivi.cpp b/libc/src/stdfix/lkdivi.cpp
new file mode 100644
index 0000000000000..82755ddfe8d38
--- /dev/null
+++ b/libc/src/stdfix/lkdivi.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of lkdivi function ---------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lkdivi.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long accum, lkdivi, (long int n, long int d)) {
+  return fixed_point::fxdivi<long accum, long int>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/lkdivi.h b/libc/src/stdfix/lkdivi.h
new file mode 100644
index 0000000000000..353ac39974622
--- /dev/null
+++ b/libc/src/stdfix/lkdivi.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for lkdivi ------------------------*- 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_STDFIX_LKDIVI_H
+#define LLVM_LIBC_SRC_STDFIX_LKDIVI_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long accum lkdivi(long int n, long int d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_LKDIVI_H
diff --git a/libc/src/stdfix/lrdivi.cpp b/libc/src/stdfix/lrdivi.cpp
new file mode 100644
index 0000000000000..31ff469835829
--- /dev/null
+++ b/libc/src/stdfix/lrdivi.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of lrdivi function ---------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lrdivi.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long fract, lrdivi, (long int n, long int d)) {
+  return fixed_point::fxdivi<long fract, long int>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/lrdivi.h b/libc/src/stdfix/lrdivi.h
new file mode 100644
index 0000000000000..9f17ac8b5667c
--- /dev/null
+++ b/libc/src/stdfix/lrdivi.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for lrdivi ------------------------*- 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_STDFIX_LRDIVI_H
+#define LLVM_LIBC_SRC_...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/210020


More information about the libc-commits mailing list