[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