[libc-commits] [libc] 5ff2774 - [libc][stdfix] Implement `idivfx` functions in LLVM libc (#133005)

via libc-commits libc-commits at lists.llvm.org
Fri Apr 25 04:58:19 PDT 2025


Author: Krishna Pandey
Date: 2025-04-25T07:58:16-04:00
New Revision: 5ff277462dd717d0c52a9a8517f624b0b484e45a

URL: https://github.com/llvm/llvm-project/commit/5ff277462dd717d0c52a9a8517f624b0b484e45a
DIFF: https://github.com/llvm/llvm-project/commit/5ff277462dd717d0c52a9a8517f624b0b484e45a.diff

LOG: [libc][stdfix] Implement `idivfx` functions in LLVM libc (#133005)

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

```c++
int idivr(fract, fract);
long int idivlr(long fract, long fract);
int idivk(accum, accum);
long int idivlk(long accum, long accum);

unsigned int idivur(unsigned fract, unsigned fract);
unsigned long int idivulr(unsigned long fract, unsigned long fract);
unsigned int idivuk(unsigned accum, unsigned accum);
unsigned long int idivulk(unsigned long accum, unsigned long accum);
```

ref: https://www.iso.org/standard/51126.html

Fixes #129125

---------

Signed-off-by: krishna2803 <kpandey81930 at gmail.com>

Added: 
    libc/src/stdfix/idivk.cpp
    libc/src/stdfix/idivk.h
    libc/src/stdfix/idivlk.cpp
    libc/src/stdfix/idivlk.h
    libc/src/stdfix/idivlr.cpp
    libc/src/stdfix/idivlr.h
    libc/src/stdfix/idivr.cpp
    libc/src/stdfix/idivr.h
    libc/src/stdfix/idivuk.cpp
    libc/src/stdfix/idivuk.h
    libc/src/stdfix/idivulk.cpp
    libc/src/stdfix/idivulk.h
    libc/src/stdfix/idivulr.cpp
    libc/src/stdfix/idivulr.h
    libc/src/stdfix/idivur.cpp
    libc/src/stdfix/idivur.h
    libc/test/src/stdfix/IdivTest.h
    libc/test/src/stdfix/idivk_test.cpp
    libc/test/src/stdfix/idivlk_test.cpp
    libc/test/src/stdfix/idivlr_test.cpp
    libc/test/src/stdfix/idivr_test.cpp
    libc/test/src/stdfix/idivuk_test.cpp
    libc/test/src/stdfix/idivulk_test.cpp
    libc/test/src/stdfix/idivulr_test.cpp
    libc/test/src/stdfix/idivur_test.cpp

Modified: 
    libc/config/baremetal/arm/entrypoints.txt
    libc/config/baremetal/riscv/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/docs/headers/stdfix.rst
    libc/include/stdfix.yaml
    libc/src/__support/fixed_point/CMakeLists.txt
    libc/src/__support/fixed_point/fx_bits.h
    libc/src/__support/macros/null_check.h
    libc/src/stdfix/CMakeLists.txt
    libc/test/src/stdfix/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 835ed023fc1dc..acafef17fa5d1 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -820,6 +820,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.countlsuhk
     libc.src.stdfix.countlsuk
     libc.src.stdfix.countlsulk
+    libc.src.stdfix.idivr
+    libc.src.stdfix.idivlr
+    libc.src.stdfix.idivk
+    libc.src.stdfix.idivlk
+    libc.src.stdfix.idivur
+    libc.src.stdfix.idivulr
+    libc.src.stdfix.idivuk
+    libc.src.stdfix.idivulk
   )
 endif()
 

diff  --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index f224e1ea336c5..023826f12d723 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -820,6 +820,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.countlsuhk
     libc.src.stdfix.countlsuk
     libc.src.stdfix.countlsulk
+    libc.src.stdfix.idivr
+    libc.src.stdfix.idivlr
+    libc.src.stdfix.idivk
+    libc.src.stdfix.idivlk
+    libc.src.stdfix.idivur
+    libc.src.stdfix.idivulr
+    libc.src.stdfix.idivuk
+    libc.src.stdfix.idivulk
   )
 endif()
 

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index e3c4fe5170104..efca4c302ad31 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -775,6 +775,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.countlsuhk
     libc.src.stdfix.countlsuk
     libc.src.stdfix.countlsulk
+    libc.src.stdfix.idivr
+    libc.src.stdfix.idivlr
+    libc.src.stdfix.idivk
+    libc.src.stdfix.idivulk
+    libc.src.stdfix.idivur
+    libc.src.stdfix.idivulr
+    libc.src.stdfix.idivuk
+    libc.src.stdfix.idivulk
   )
 endif()
 

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 641e0a942e7bd..b598670ebc7da 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -920,6 +920,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
     libc.src.stdfix.countlsuhk
     libc.src.stdfix.countlsuk
     libc.src.stdfix.countlsulk
+    libc.src.stdfix.idivr
+    libc.src.stdfix.idivlr
+    libc.src.stdfix.idivk
+    libc.src.stdfix.idivlk
+    libc.src.stdfix.idivur
+    libc.src.stdfix.idivulr
+    libc.src.stdfix.idivuk
+    libc.src.stdfix.idivulk
   )
 endif()
 

diff  --git a/libc/docs/headers/stdfix.rst b/libc/docs/headers/stdfix.rst
index 20f68b4a1ed35..a2f5e94774798 100644
--- a/libc/docs/headers/stdfix.rst
+++ b/libc/docs/headers/stdfix.rst
@@ -77,7 +77,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard.
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
 | divi\*        |                |             |               |            |                |             |                |             |               |            |                |             |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
-| idiv\*        |                |             |               |            |                |             |                |             |               |            |                |             |
+| idiv\*        | |check|        | |check|     | |check|       | |check|    | |check|        | |check|     | |check|        | |check|     | |check|       | |check|    | |check|        | |check|     |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
 | muli          |                |             |               |            |                |             |                |             |               |            |                |             |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+

diff  --git a/libc/include/stdfix.yaml b/libc/include/stdfix.yaml
index 29c4d8b5c8960..5b385124eb63d 100644
--- a/libc/include/stdfix.yaml
+++ b/libc/include/stdfix.yaml
@@ -238,6 +238,70 @@ functions:
     arguments:
       - type: unsigned long accum
     guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivr
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: fract
+      - type: fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivlr
+    standards:
+      - stdc_ext
+    return_type: long int
+    arguments:
+      - type: long fract
+      - type: long fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: accum
+      - type: accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivlk
+    standards:
+      - stdc_ext
+    return_type: long int
+    arguments:
+      - type: long accum
+      - type: long accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivur
+    standards:
+      - stdc_ext
+    return_type: unsigned int
+    arguments:
+      - type: unsigned fract
+      - type: unsigned fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivulr
+    standards:
+      - stdc_ext
+    return_type: unsigned long int
+    arguments:
+      - type: unsigned long fract
+      - type: unsigned long fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivuk
+    standards:
+      - stdc_ext
+    return_type: unsigned int
+    arguments:
+      - type: unsigned accum
+      - type: unsigned accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: idivulk
+    standards:
+      - stdc_ext
+    return_type: unsigned long int
+    arguments:
+      - type: unsigned long accum
+      - type: unsigned long accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
   - name: roundhk
     standards:
       - stdc_ext

diff  --git a/libc/src/__support/fixed_point/CMakeLists.txt b/libc/src/__support/fixed_point/CMakeLists.txt
index b415e2c00c488..235c03048cfa4 100644
--- a/libc/src/__support/fixed_point/CMakeLists.txt
+++ b/libc/src/__support/fixed_point/CMakeLists.txt
@@ -16,6 +16,7 @@ add_header_library(
     .fx_rep
     libc.include.llvm-libc-macros.stdfix_macros
     libc.src.__support.macros.attributes
+    libc.src.__support.macros.null_check
     libc.src.__support.macros.optimization
     libc.src.__support.CPP.type_traits
     libc.src.__support.CPP.bit

diff  --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index b05f46bd34660..00c6119b4f353 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -15,6 +15,7 @@
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/macros/attributes.h"   // LIBC_INLINE
 #include "src/__support/macros/config.h"       // LIBC_NAMESPACE_DECL
+#include "src/__support/macros/null_check.h"   // LIBC_CRASH_ON_VALUE
 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
 #include "src/__support/math_extras.h"
 
@@ -201,6 +202,28 @@ bitsfx(T f) {
   return cpp::bit_cast<XType, T>(f);
 }
 
+// divide the two fixed-point types and return an integer result
+template <typename T, typename XType>
+LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, XType>
+idiv(T x, T y) {
+  using FXBits = FXBits<T>;
+  using FXRep = FXRep<T>;
+  using CompType = typename FXRep::CompType;
+
+  // 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(y, FXRep::ZERO());
+
+  CompType x_comp = static_cast<CompType>(FXBits(x).get_bits());
+  CompType y_comp = static_cast<CompType>(FXBits(y).get_bits());
+
+  // If an integer result of one of these functions overflows, the behavior is
+  // undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16
+  CompType result = x_comp / y_comp;
+
+  return static_cast<XType>(result);
+}
+
 } // namespace fixed_point
 } // namespace LIBC_NAMESPACE_DECL
 

diff  --git a/libc/src/__support/macros/null_check.h b/libc/src/__support/macros/null_check.h
index eda19f889235e..abf65c56c404b 100644
--- a/libc/src/__support/macros/null_check.h
+++ b/libc/src/__support/macros/null_check.h
@@ -19,10 +19,19 @@
     if (LIBC_UNLIKELY((ptr) == nullptr))                                       \
       __builtin_trap();                                                        \
   } while (0)
+#define LIBC_CRASH_ON_VALUE(var, value)                                        \
+  do {                                                                         \
+    if (LIBC_UNLIKELY((var) == (value)))                                       \
+      __builtin_trap();                                                        \
+  } while (0)
+
 #else
 #define LIBC_CRASH_ON_NULLPTR(ptr)                                             \
   do {                                                                         \
   } while (0)
+#define LIBC_CRASH_ON_VALUE(var, value)                                        \
+  do {                                                                         \
+  } while (0)
 #endif
 
 #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_NULL_CHECK_H

diff  --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
index 362af0bf0d55c..843111e3f80b1 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -75,6 +75,20 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
   )
 endforeach()
 
+foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
+  add_entrypoint_object(
+    idiv${suffix}
+    HDRS
+      idiv${suffix}.h
+    SRCS
+      idiv${suffix}.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/src/stdfix/idivk.cpp b/libc/src/stdfix/idivk.cpp
new file mode 100644
index 0000000000000..d1d758dc56995
--- /dev/null
+++ b/libc/src/stdfix/idivk.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of idivk 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 "idivk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // accum
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, idivk, (accum x, accum y)) {
+  return fixed_point::idiv<accum, int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivk.h b/libc/src/stdfix/idivk.h
new file mode 100644
index 0000000000000..a84bd0da2d533
--- /dev/null
+++ b/libc/src/stdfix/idivk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivk ------------------------*- 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_IDIVK_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // accum
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+int idivk(accum x, accum y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVK_H

diff  --git a/libc/src/stdfix/idivlk.cpp b/libc/src/stdfix/idivlk.cpp
new file mode 100644
index 0000000000000..36e1df6cc58fb
--- /dev/null
+++ b/libc/src/stdfix/idivlk.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of idivlk 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 "idivlk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // long accum
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long int, idivlk, (long accum x, long accum y)) {
+  return fixed_point::idiv<long accum, long int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivlk.h b/libc/src/stdfix/idivlk.h
new file mode 100644
index 0000000000000..274a61a9d82c3
--- /dev/null
+++ b/libc/src/stdfix/idivlk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivlk -----------------------*- 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_IDIVLK_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVLK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // long accum
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+long int idivlk(long accum x, long accum y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVLK_H

diff  --git a/libc/src/stdfix/idivlr.cpp b/libc/src/stdfix/idivlr.cpp
new file mode 100644
index 0000000000000..1c9d62d196a29
--- /dev/null
+++ b/libc/src/stdfix/idivlr.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of idivlr 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 "idivlr.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // long fract
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long int, idivlr, (long fract x, long fract y)) {
+  return fixed_point::idiv<long fract, long int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivlr.h b/libc/src/stdfix/idivlr.h
new file mode 100644
index 0000000000000..de36035f289a4
--- /dev/null
+++ b/libc/src/stdfix/idivlr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivlr -----------------------*- 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_IDIVLR_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVLR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // long fract
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+long int idivlr(long fract x, long fract y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVLR_H

diff  --git a/libc/src/stdfix/idivr.cpp b/libc/src/stdfix/idivr.cpp
new file mode 100644
index 0000000000000..80dd1b2107272
--- /dev/null
+++ b/libc/src/stdfix/idivr.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of idivr 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 "idivr.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // fract
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, idivr, (fract x, fract y)) {
+  return fixed_point::idiv<fract, int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivr.h b/libc/src/stdfix/idivr.h
new file mode 100644
index 0000000000000..f3a95e2d516c3
--- /dev/null
+++ b/libc/src/stdfix/idivr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivr ------------------------*- 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_IDIVR_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // fract
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+int idivr(fract x, fract y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVR_H

diff  --git a/libc/src/stdfix/idivuk.cpp b/libc/src/stdfix/idivuk.cpp
new file mode 100644
index 0000000000000..27bf8edd80927
--- /dev/null
+++ b/libc/src/stdfix/idivuk.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of idivuk 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 "idivuk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned accum
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned int, idivuk, (unsigned accum x, unsigned accum y)) {
+  return fixed_point::idiv<unsigned accum, unsigned int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivuk.h b/libc/src/stdfix/idivuk.h
new file mode 100644
index 0000000000000..a8dce0a0b4c8b
--- /dev/null
+++ b/libc/src/stdfix/idivuk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivuk ------------------------*- 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_IDIVUK_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVUK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned accum
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned int idivuk(unsigned accum x, unsigned accum y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVUK_H

diff  --git a/libc/src/stdfix/idivulk.cpp b/libc/src/stdfix/idivulk.cpp
new file mode 100644
index 0000000000000..8b4e63c1b78fb
--- /dev/null
+++ b/libc/src/stdfix/idivulk.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of idivulk 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 "idivulk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long accum
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned long int, idivulk,
+                   (unsigned long accum x, unsigned long accum y)) {
+  return fixed_point::idiv<unsigned long accum, unsigned long int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivulk.h b/libc/src/stdfix/idivulk.h
new file mode 100644
index 0000000000000..b463e76b98f5e
--- /dev/null
+++ b/libc/src/stdfix/idivulk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivlk -----------------------*- 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_IDIVULK_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVULK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long accum
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned long int idivulk(unsigned long accum x, unsigned long accum y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVULK_H

diff  --git a/libc/src/stdfix/idivulr.cpp b/libc/src/stdfix/idivulr.cpp
new file mode 100644
index 0000000000000..6e6a780c1b8c5
--- /dev/null
+++ b/libc/src/stdfix/idivulr.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of idivulr 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 "idivulr.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long fract
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned long int, idivulr,
+                   (unsigned long fract x, unsigned long fract y)) {
+  return fixed_point::idiv<unsigned long fract, unsigned long int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivulr.h b/libc/src/stdfix/idivulr.h
new file mode 100644
index 0000000000000..c2f6a1911bd37
--- /dev/null
+++ b/libc/src/stdfix/idivulr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivulr ----------------------*- 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_IDIVULR_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVULR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long fract
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned long int idivulr(unsigned long fract x, unsigned long fract y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVULR_H

diff  --git a/libc/src/stdfix/idivur.cpp b/libc/src/stdfix/idivur.cpp
new file mode 100644
index 0000000000000..319817b9662d3
--- /dev/null
+++ b/libc/src/stdfix/idivur.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of idivur 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 "idivur.h"
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned fract
+#include "src/__support/common.h"                   // LLVM_LIBC_FUNCTION
+#include "src/__support/fixed_point/fx_bits.h"      // fixed_point
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned int, idivur, (unsigned fract x, unsigned fract y)) {
+  return fixed_point::idiv<unsigned fract, unsigned int>(x, y);
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/stdfix/idivur.h b/libc/src/stdfix/idivur.h
new file mode 100644
index 0000000000000..f69db20bcf512
--- /dev/null
+++ b/libc/src/stdfix/idivur.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for idivur -----------------------*- 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_IDIVUR_H
+#define LLVM_LIBC_SRC_STDFIX_IDIVUR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned fract
+#include "src/__support/macros/config.h"            // LIBC_NAMESPACE_DECL
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned int idivur(unsigned fract x, unsigned fract y);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_IDIVUR_H

diff  --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt
index a3dc25762f549..e2b4bc1805f7c 100644
--- a/libc/test/src/stdfix/CMakeLists.txt
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -104,6 +104,22 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
   )
 endforeach()
 
+foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
+  add_libc_test(
+    idiv${suffix}_test
+    SUITE
+      libc-stdfix-tests
+    HDRS
+      IdivTest.h
+    SRCS
+      idiv${suffix}_test.cpp
+    DEPENDS
+      libc.src.stdfix.idiv${suffix}
+      libc.src.__support.fixed_point.fx_bits
+      libc.hdr.signal_macros
+  )
+endforeach()
+
 add_libc_test(
   uhksqrtus_test
   SUITE

diff  --git a/libc/test/src/stdfix/IdivTest.h b/libc/test/src/stdfix/IdivTest.h
new file mode 100644
index 0000000000000..6bfe9dff01a39
--- /dev/null
+++ b/libc/test/src/stdfix/IdivTest.h
@@ -0,0 +1,91 @@
+//===-- Utility class to test idivfx functions ------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "test/UnitTest/Test.h"
+
+#include "src/__support/fixed_point/fx_rep.h"
+#include "src/__support/macros/sanitizer.h"
+
+#include "hdr/signal_macros.h"
+
+template <typename T, typename XType>
+class IdivTest : public LIBC_NAMESPACE::testing::Test {
+
+  using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<T>;
+
+  static constexpr T zero = FXRep::ZERO();
+  static constexpr T max = FXRep::MAX();
+  static constexpr T min = FXRep::MIN();
+  static constexpr T one_half = FXRep::ONE_HALF();
+  static constexpr T one_fourth = FXRep::ONE_FOURTH();
+
+public:
+  typedef XType (*IdivFunc)(T, T);
+
+  void testSpecialNumbers(IdivFunc func) {
+    constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
+    constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
+
+    EXPECT_EQ(func(one_half, one_fourth), static_cast<XType>(2));
+    EXPECT_EQ(func(one_half, one_half), static_cast<XType>(1));
+    EXPECT_EQ(func(one_fourth, one_half), static_cast<XType>(0));
+    EXPECT_EQ(func(0.75, 0.25), static_cast<XType>(3));
+    EXPECT_EQ(func(0.625, 0.125), static_cast<XType>(5));
+
+    if constexpr (is_signed) {
+      EXPECT_EQ(func(min, one_half), static_cast<XType>(min) * 2);
+    } else {
+      EXPECT_EQ(func(min, one_half), static_cast<XType>(0));
+    }
+
+    if constexpr (has_integral && min <= 7 && max >= 5) {
+      EXPECT_EQ(func(6.9, 4.2), static_cast<XType>(1));
+      EXPECT_EQ(func(4.2, 6.9), static_cast<XType>(0));
+      EXPECT_EQ(func(4.5, 2.2), static_cast<XType>(2));
+      EXPECT_EQ(func(2.2, 1.1), static_cast<XType>(2));
+      EXPECT_EQ(func(2.25, 1.0), static_cast<XType>(2));
+      EXPECT_EQ(func(2.25, 3.0), static_cast<XType>(0));
+
+      if constexpr (is_signed) {
+        EXPECT_EQ(func(4.2, -6.9), static_cast<XType>(0));
+        EXPECT_EQ(func(-6.9, 4.2), static_cast<XType>(-1));
+        EXPECT_EQ(func(-2.5, 1.25), static_cast<XType>(-2));
+        EXPECT_EQ(func(-2.25, 1.0), static_cast<XType>(-2));
+        EXPECT_EQ(func(2.25, -3.0), static_cast<XType>(0));
+      }
+    }
+  }
+
+  void testInvalidNumbers(IdivFunc func) {
+    constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
+
+    EXPECT_DEATH([func] { func(0.5, 0.0); }, WITH_SIGNAL(SIGILL));
+    if constexpr (has_integral) {
+      EXPECT_DEATH([func] { func(2.5, 0.0); }, WITH_SIGNAL(SIGSEGV));
+    }
+  }
+};
+
+#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
+#define LIST_IDIV_TESTS(Name, T, XTYpe, func)                                  \
+  using LlvmLibcIdiv##Name##Test = IdivTest<T, XType>;                         \
+  TEST_F(LlvmLibcIdiv##Name##Test, InvalidNumbers) {                           \
+    testInvalidNumbers(&func);                                                 \
+  }                                                                            \
+  TEST_F(LlvmLibcIdiv##Name##Test, SpecialNumbers) {                           \
+    testSpecialNumbers(&func);                                                 \
+  }                                                                            \
+  static_assert(true, "Require semicolon.")
+#else
+#define LIST_IDIV_TESTS(Name, T, XType, func)                                  \
+  using LlvmLibcIdiv##Name##Test = IdivTest<T, XType>;                         \
+  TEST_F(LlvmLibcIdiv##Name##Test, SpecialNumbers) {                           \
+    testSpecialNumbers(&func);                                                 \
+  }                                                                            \
+  static_assert(true, "Require semicolon.")
+#endif // LIBC_HAS_ADDRESS_SANITIZER

diff  --git a/libc/test/src/stdfix/idivk_test.cpp b/libc/test/src/stdfix/idivk_test.cpp
new file mode 100644
index 0000000000000..b10a43ed6135a
--- /dev/null
+++ b/libc/test/src/stdfix/idivk_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for idivk -----------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // accum
+#include "src/stdfix/idivk.h"
+
+LIST_IDIV_TESTS(k, accum, int, LIBC_NAMESPACE::idivk);

diff  --git a/libc/test/src/stdfix/idivlk_test.cpp b/libc/test/src/stdfix/idivlk_test.cpp
new file mode 100644
index 0000000000000..dcd4ccbcc4a78
--- /dev/null
+++ b/libc/test/src/stdfix/idivlk_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for idivlk ----------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // long accum
+#include "src/stdfix/idivlk.h"
+
+LIST_IDIV_TESTS(lk, long accum, long int, LIBC_NAMESPACE::idivlk);

diff  --git a/libc/test/src/stdfix/idivlr_test.cpp b/libc/test/src/stdfix/idivlr_test.cpp
new file mode 100644
index 0000000000000..0fdb1e3a19e8f
--- /dev/null
+++ b/libc/test/src/stdfix/idivlr_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for idivlr ----------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // long fract
+#include "src/stdfix/idivlr.h"
+
+LIST_IDIV_TESTS(lr, long fract, long int, LIBC_NAMESPACE::idivlr);

diff  --git a/libc/test/src/stdfix/idivr_test.cpp b/libc/test/src/stdfix/idivr_test.cpp
new file mode 100644
index 0000000000000..82bec5c7be069
--- /dev/null
+++ b/libc/test/src/stdfix/idivr_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for idivr -----------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // fract
+#include "src/stdfix/idivr.h"
+
+LIST_IDIV_TESTS(r, fract, int, LIBC_NAMESPACE::idivr);

diff  --git a/libc/test/src/stdfix/idivuk_test.cpp b/libc/test/src/stdfix/idivuk_test.cpp
new file mode 100644
index 0000000000000..2bfd93da3ed4a
--- /dev/null
+++ b/libc/test/src/stdfix/idivuk_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for idivuk ----------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // unsigned accum
+#include "src/stdfix/idivuk.h"
+
+LIST_IDIV_TESTS(uk, unsigned accum, unsigned int, LIBC_NAMESPACE::idivuk);

diff  --git a/libc/test/src/stdfix/idivulk_test.cpp b/libc/test/src/stdfix/idivulk_test.cpp
new file mode 100644
index 0000000000000..31eb96114a0ce
--- /dev/null
+++ b/libc/test/src/stdfix/idivulk_test.cpp
@@ -0,0 +1,15 @@
+//===-- Unittests for idivulk ---------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // unsigned long accum
+#include "src/stdfix/idivulk.h"
+
+LIST_IDIV_TESTS(ulk, unsigned long accum, unsigned long int,
+                LIBC_NAMESPACE::idivulk);

diff  --git a/libc/test/src/stdfix/idivulr_test.cpp b/libc/test/src/stdfix/idivulr_test.cpp
new file mode 100644
index 0000000000000..6f43df149a127
--- /dev/null
+++ b/libc/test/src/stdfix/idivulr_test.cpp
@@ -0,0 +1,15 @@
+//===-- Unittests for idivulr ---------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // unsigned long fract
+#include "src/stdfix/idivulr.h"
+
+LIST_IDIV_TESTS(ulr, unsigned long fract, unsigned long int,
+                LIBC_NAMESPACE::idivulr);

diff  --git a/libc/test/src/stdfix/idivur_test.cpp b/libc/test/src/stdfix/idivur_test.cpp
new file mode 100644
index 0000000000000..c2d2f9caf19d9
--- /dev/null
+++ b/libc/test/src/stdfix/idivur_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for idivur ----------------------------------------------===//
+//
+// 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 "IdivTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // unsigned fract
+#include "src/stdfix/idivur.h"
+
+LIST_IDIV_TESTS(ur, unsigned fract, unsigned int, LIBC_NAMESPACE::idivur);


        


More information about the libc-commits mailing list