[libc-commits] [libc] [libc][stdfix] Implement divifx functions in LLVM libc (PR #206115)
via libc-commits
libc-commits at lists.llvm.org
Wed Jul 8 03:16:08 PDT 2026
https://github.com/sohail103 updated https://github.com/llvm/llvm-project/pull/206115
>From 6c54655ee4a93a0501231461fb13f0ad2f7bdb7e Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Fri, 26 Jun 2026 13:04:10 +0530
Subject: [PATCH 1/7] [libc][stdfix] add divir implementation
---
libc/config/baremetal/arm/entrypoints.txt | 1 +
libc/config/baremetal/riscv/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/docs/headers/stdfix.rst | 2 +-
libc/include/stdfix.yaml | 8 ++
libc/src/__support/fixed_point/CMakeLists.txt | 1 +
libc/src/__support/fixed_point/fx_bits.h | 46 +++++++++++
libc/src/stdfix/CMakeLists.txt | 14 ++++
libc/src/stdfix/divir.cpp | 21 +++++
libc/src/stdfix/divir.h | 21 +++++
libc/test/src/stdfix/CMakeLists.txt | 17 ++++
libc/test/src/stdfix/DiviFxTest.h | 80 +++++++++++++++++++
libc/test/src/stdfix/divir_test.cpp | 14 ++++
14 files changed, 227 insertions(+), 1 deletion(-)
create mode 100644 libc/src/stdfix/divir.cpp
create mode 100644 libc/src/stdfix/divir.h
create mode 100644 libc/test/src/stdfix/DiviFxTest.h
create mode 100644 libc/test/src/stdfix/divir_test.cpp
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index a5c1b20a7a434..8c592f211a4e1 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -970,6 +970,7 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivulr
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
+ libc.src.stdfix.divir
)
endif()
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 60bc924993fc8..03b48cbd4e3f6 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -967,6 +967,7 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivulr
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
+ libc.src.stdfix.divir
)
endif()
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 2508de5cfe5a4..a1d5836307ba8 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1102,6 +1102,7 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.rdivi
+ libc.src.stdfix.divir
)
endif()
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5ace968a739c8..059a171662b75 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1173,6 +1173,7 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.rdivi
+ libc.src.stdfix.divir
)
endif()
diff --git a/libc/docs/headers/stdfix.rst b/libc/docs/headers/stdfix.rst
index 76ac7e7b71c95..84294a4e14792 100644
--- a/libc/docs/headers/stdfix.rst
+++ b/libc/docs/headers/stdfix.rst
@@ -73,7 +73,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard.
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| countls | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
-| divi\* | | | | | | | | | | | | |
+| divi\* | | | | |check| | | | | | | | | |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| idiv\* | |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 8b7485555c080..4f3cfa39ce974 100644
--- a/libc/include/stdfix.yaml
+++ b/libc/include/stdfix.yaml
@@ -565,3 +565,11 @@ functions:
- type: int
- type: int
guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: divir
+ standards:
+ - stdc_ext
+ return_type: int
+ arguments:
+ - type: int
+ - type: fract
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
diff --git a/libc/src/__support/fixed_point/CMakeLists.txt b/libc/src/__support/fixed_point/CMakeLists.txt
index 145eedb6ae8e7..c1b0ab30e0307 100644
--- a/libc/src/__support/fixed_point/CMakeLists.txt
+++ b/libc/src/__support/fixed_point/CMakeLists.txt
@@ -23,6 +23,7 @@ add_header_library(
libc.src.__support.CPP.bit
libc.src.__support.CPP.limits
libc.src.__support.math_extras
+ libc.src.__support.uint128
)
add_header_library(
diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index 91814bda7dd7e..8622040e2215e 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -14,12 +14,14 @@
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/limits.h" // numeric_limits
#include "src/__support/CPP/type_traits.h"
+#include "src/__support/CPP/type_traits/conditional.h"
#include "src/__support/libc_assert.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"
+#include "src/__support/uint128.h"
#include "fx_rep.h"
@@ -333,6 +335,50 @@ template <typename XType> LIBC_INLINE constexpr XType divi(int n, int d) {
}
}
+// divide an integer operand by a fixed-point operand and return the
+// mathematically exact result as an IntType rounded towards 0. assumes
+// signedness of IntType matches the signedness of FXType. all divifx variants
+// satisfy this requirement.
+template <typename IntType, typename FXType>
+LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<FXType>, IntType>
+divifx(IntType n, FXType d) {
+ using FXBits = FXBits<FXType>;
+ using FXRep = FXRep<FXType>;
+ using CompType = typename FXRep::CompType;
+
+ static_assert(cpp::is_signed_v<IntType> == (FXRep::SIGN_LEN > 0),
+ "IntType and FXType must have matching signedness");
+
+ // UB if denominator is 0
+ LIBC_CRASH_ON_VALUE(d, FXRep::ZERO());
+
+ if (LIBC_UNLIKELY(n == 0)) {
+ return static_cast<IntType>(0);
+ }
+
+ // get integer representation of denominator
+ CompType d_comp = static_cast<CompType>(FXBits(d).get_bits());
+
+ constexpr int F = FXRep::FRACTION_LEN;
+
+ // calculating the required number of bits to represent n*2^F without
+ // overflowing
+ constexpr int INTERMEDIATE_BITS =
+ sizeof(IntType) * 8 - cpp::is_signed_v<IntType> + F;
+
+ // use 64 or 128 bit intermediates depending on INTERMEDIATE_BITS
+ using WideType = cpp::conditional_t<
+ cpp::is_signed_v<IntType>,
+ cpp::conditional_t<INTERMEDIATE_BITS <= 64, int64_t, Int128>,
+ cpp::conditional_t<INTERMEDIATE_BITS <= 64, uint64_t, UInt128>>;
+
+ // (n*2^F/d)
+ WideType scaled_n = static_cast<WideType>(n) << F;
+ WideType result = scaled_n / static_cast<WideType>(d_comp);
+
+ return static_cast<IntType>(result);
+}
+
} // namespace fixed_point
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
index e9841cd940315..f7b48b375cdba 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -102,6 +102,20 @@ foreach(suffix IN ITEMS r)
)
endforeach()
+foreach(suffix IN ITEMS r)
+ add_entrypoint_object(
+ divi${suffix}
+ HDRS
+ divi${suffix}.h
+ SRCS
+ divi${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/divir.cpp b/libc/src/stdfix/divir.cpp
new file mode 100644
index 0000000000000..990db419ef1b6
--- /dev/null
+++ b/libc/src/stdfix/divir.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of divir 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 "divir.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, divir, (int n, fract d)) {
+ return fixed_point::divifx<int, fract>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/divir.h b/libc/src/stdfix/divir.h
new file mode 100644
index 0000000000000..f54dcd9e8ca32
--- /dev/null
+++ b/libc/src/stdfix/divir.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for divir ------------------------*- 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_DIVIR_H
+#define LLVM_LIBC_SRC_STDFIX_DIVIR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int divir(int n, fract d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVIR_H
diff --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt
index 04bedc3e00fe2..3bf3051c6b85a 100644
--- a/libc/test/src/stdfix/CMakeLists.txt
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -147,6 +147,23 @@ foreach(suffix IN ITEMS r)
)
endforeach()
+foreach(suffix IN ITEMS r)
+ add_libc_test(
+ divi${suffix}_test
+ SUITE
+ libc-stdfix-tests
+ HDRS
+ DiviFxTest.h
+ SRCS
+ divi${suffix}_test.cpp
+ DEPENDS
+ libc.src.stdfix.divi${suffix}
+ libc.src.__support.fixed_point.fx_rep
+ 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/DiviFxTest.h b/libc/test/src/stdfix/DiviFxTest.h
new file mode 100644
index 0000000000000..c3e0b8ac038e9
--- /dev/null
+++ b/libc/test/src/stdfix/DiviFxTest.h
@@ -0,0 +1,80 @@
+//===-- Utility class to test divifx 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 "hdr/signal_macros.h"
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/fixed_point/fx_rep.h"
+
+template <typename IntType, typename FXType>
+class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
+
+ using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<FXType>;
+
+ static constexpr FXType zero = FXRep::ZERO();
+ static constexpr FXType min = FXRep::MIN();
+ static constexpr FXType one_half = FXRep::ONE_HALF();
+ static constexpr FXType one_fourth = FXRep::ONE_FOURTH();
+
+public:
+ typedef IntType (*DiviFxFunc)(IntType, FXType);
+
+ void testBasicNumbers(DiviFxFunc func) {
+ constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
+
+ EXPECT_EQ(func(1, one_fourth), static_cast<IntType>(4));
+ EXPECT_EQ(func(1, one_half), static_cast<IntType>(2));
+ EXPECT_EQ(func(1, 0.125r), static_cast<IntType>(8));
+ EXPECT_EQ(func(2, one_fourth), static_cast<IntType>(8));
+ EXPECT_EQ(func(2, one_half), static_cast<IntType>(4));
+ EXPECT_EQ(func(2, 0.125r), static_cast<IntType>(16));
+
+ // verify rounding towards 0
+ EXPECT_EQ(func(1, 3 * one_fourth), static_cast<IntType>(1));
+ EXPECT_EQ(func(2, 3 * one_fourth), static_cast<IntType>(2));
+
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(-1, one_half), static_cast<IntType>(-2));
+ EXPECT_EQ(func(1, -one_half), static_cast<IntType>(-2));
+ EXPECT_EQ(func(-1, -one_half), static_cast<IntType>(2));
+ EXPECT_EQ(func(-2, one_fourth), static_cast<IntType>(-8));
+ EXPECT_EQ(func(2, -one_fourth), static_cast<IntType>(-8));
+
+ // verify rounding towards 0
+ EXPECT_EQ(func(-1, 3 * one_fourth), static_cast<IntType>(-1));
+ EXPECT_EQ(func(1, -3 * one_fourth), static_cast<IntType>(-1));
+ EXPECT_EQ(func(-2, 3 * one_fourth), static_cast<IntType>(-2));
+ EXPECT_EQ(func(2, -3 * one_fourth), static_cast<IntType>(-2));
+ } else {
+ // min of unsigned type = 0
+ EXPECT_EQ(func(min, one_half), static_cast<IntType>(0));
+ EXPECT_EQ(func(min, one_fourth), static_cast<IntType>(0));
+ }
+ }
+
+ void testInvalidNumbers(DiviFxFunc func) {
+ EXPECT_DEATH([func] { func(1, zero); }, WITH_SIGNAL(-1));
+ }
+};
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+#define LIST_DIVIFX_TESTS(Name, IntType, FXType, func) \
+ using LlvmLibcDivi##Name##Test = DiviFxTest<IntType, FXType>; \
+ TEST_F(LlvmLibcDivi##Name##Test, InvalidNumbers) { \
+ testInvalidNumbers(&func); \
+ } \
+ TEST_F(LlvmLibcDivi##Name##Test, BasicNumbers) { testBasicNumbers(&func); } \
+ static_assert(true, "Require semicolon.")
+#else
+#define LIST_DIVIFX_TESTS(Name, IntType, FXType, func) \
+ using LlvmLibcDivi##Name##Test = DiviFxTest<IntType, FXType>; \
+ TEST_F(LlvmLibcDivi##Name##Test, BasicNumbers) { testBasicNumbers(&func); } \
+ static_assert(true, "Require semicolon.")
+#endif // LIBC_ADD_NULL_CHECKS
diff --git a/libc/test/src/stdfix/divir_test.cpp b/libc/test/src/stdfix/divir_test.cpp
new file mode 100644
index 0000000000000..97f8dab63afba
--- /dev/null
+++ b/libc/test/src/stdfix/divir_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for divir -----------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h" // fract
+#include "src/stdfix/divir.h"
+
+LIST_DIVIFX_TESTS(r, int, fract, LIBC_NAMESPACE::divir);
>From e46bbc429fb729b3d87048fd679807b7a5d7d348 Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Fri, 26 Jun 2026 20:57:59 +0530
Subject: [PATCH 2/7] [libc][stdfix] implement remaining divifx functions along
with tests
---
libc/config/baremetal/arm/entrypoints.txt | 7 +++
libc/config/baremetal/riscv/entrypoints.txt | 7 +++
libc/config/linux/riscv/entrypoints.txt | 7 +++
libc/config/linux/x86_64/entrypoints.txt | 7 +++
libc/docs/headers/stdfix.rst | 2 +-
libc/include/stdfix.yaml | 56 +++++++++++++++++++++
libc/src/stdfix/CMakeLists.txt | 2 +-
libc/src/stdfix/divik.cpp | 21 ++++++++
libc/src/stdfix/divik.h | 21 ++++++++
libc/src/stdfix/divilk.cpp | 21 ++++++++
libc/src/stdfix/divilk.h | 21 ++++++++
libc/src/stdfix/divilr.cpp | 21 ++++++++
libc/src/stdfix/divilr.h | 21 ++++++++
libc/src/stdfix/diviuk.cpp | 20 ++++++++
libc/src/stdfix/diviuk.h | 21 ++++++++
libc/src/stdfix/diviulk.cpp | 22 ++++++++
libc/src/stdfix/diviulk.h | 21 ++++++++
libc/src/stdfix/diviulr.cpp | 21 ++++++++
libc/src/stdfix/diviulr.h | 21 ++++++++
libc/src/stdfix/diviur.cpp | 21 ++++++++
libc/src/stdfix/diviur.h | 21 ++++++++
libc/test/src/stdfix/CMakeLists.txt | 2 +-
libc/test/src/stdfix/DiviFxTest.h | 33 ++++++++++--
libc/test/src/stdfix/divik_test.cpp | 14 ++++++
libc/test/src/stdfix/divilk_test.cpp | 14 ++++++
libc/test/src/stdfix/divilr_test.cpp | 14 ++++++
libc/test/src/stdfix/divir_test.cpp | 2 +-
libc/test/src/stdfix/diviuk_test.cpp | 14 ++++++
libc/test/src/stdfix/diviulk_test.cpp | 15 ++++++
libc/test/src/stdfix/diviulr_test.cpp | 15 ++++++
libc/test/src/stdfix/diviur_test.cpp | 14 ++++++
31 files changed, 511 insertions(+), 8 deletions(-)
create mode 100644 libc/src/stdfix/divik.cpp
create mode 100644 libc/src/stdfix/divik.h
create mode 100644 libc/src/stdfix/divilk.cpp
create mode 100644 libc/src/stdfix/divilk.h
create mode 100644 libc/src/stdfix/divilr.cpp
create mode 100644 libc/src/stdfix/divilr.h
create mode 100644 libc/src/stdfix/diviuk.cpp
create mode 100644 libc/src/stdfix/diviuk.h
create mode 100644 libc/src/stdfix/diviulk.cpp
create mode 100644 libc/src/stdfix/diviulk.h
create mode 100644 libc/src/stdfix/diviulr.cpp
create mode 100644 libc/src/stdfix/diviulr.h
create mode 100644 libc/src/stdfix/diviur.cpp
create mode 100644 libc/src/stdfix/diviur.h
create mode 100644 libc/test/src/stdfix/divik_test.cpp
create mode 100644 libc/test/src/stdfix/divilk_test.cpp
create mode 100644 libc/test/src/stdfix/divilr_test.cpp
create mode 100644 libc/test/src/stdfix/diviuk_test.cpp
create mode 100644 libc/test/src/stdfix/diviulk_test.cpp
create mode 100644 libc/test/src/stdfix/diviulr_test.cpp
create mode 100644 libc/test/src/stdfix/diviur_test.cpp
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 8c592f211a4e1..894c6dcd760c7 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -971,6 +971,13 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.divir
+ libc.src.stdfix.divilr
+ libc.src.stdfix.divik
+ libc.src.stdfix.divilk
+ libc.src.stdfix.diviur
+ libc.src.stdfix.diviulr
+ libc.src.stdfix.diviuk
+ libc.src.stdfix.diviulk
)
endif()
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 03b48cbd4e3f6..4194135f50a0c 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -968,6 +968,13 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.divir
+ libc.src.stdfix.divilr
+ libc.src.stdfix.divik
+ libc.src.stdfix.divilk
+ libc.src.stdfix.diviur
+ libc.src.stdfix.diviulr
+ libc.src.stdfix.diviuk
+ libc.src.stdfix.diviulk
)
endif()
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index a1d5836307ba8..33e588d9aa837 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1103,6 +1103,13 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivulk
libc.src.stdfix.rdivi
libc.src.stdfix.divir
+ libc.src.stdfix.divilr
+ libc.src.stdfix.divik
+ libc.src.stdfix.divilk
+ libc.src.stdfix.diviur
+ libc.src.stdfix.diviulr
+ libc.src.stdfix.diviuk
+ libc.src.stdfix.diviulk
)
endif()
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 059a171662b75..96cbebdfa1609 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1174,6 +1174,13 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivulk
libc.src.stdfix.rdivi
libc.src.stdfix.divir
+ libc.src.stdfix.divilr
+ libc.src.stdfix.divik
+ libc.src.stdfix.divilk
+ libc.src.stdfix.diviur
+ libc.src.stdfix.diviulr
+ libc.src.stdfix.diviuk
+ libc.src.stdfix.diviulk
)
endif()
diff --git a/libc/docs/headers/stdfix.rst b/libc/docs/headers/stdfix.rst
index 84294a4e14792..efb836f964fa2 100644
--- a/libc/docs/headers/stdfix.rst
+++ b/libc/docs/headers/stdfix.rst
@@ -73,7 +73,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard.
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| countls | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
-| divi\* | | | | |check| | | | | | | | | |
+| divi\* | | | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| idiv\* | |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 4f3cfa39ce974..f91e4ea620e3e 100644
--- a/libc/include/stdfix.yaml
+++ b/libc/include/stdfix.yaml
@@ -573,3 +573,59 @@ functions:
- type: int
- type: fract
guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: divilr
+ standards:
+ - stdc_ext
+ return_type: long int
+ arguments:
+ - type: long int
+ - type: long fract
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: divik
+ standards:
+ - stdc_ext
+ return_type: int
+ arguments:
+ - type: int
+ - type: accum
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: divilk
+ standards:
+ - stdc_ext
+ return_type: long int
+ arguments:
+ - type: long int
+ - type: long accum
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: diviur
+ standards:
+ - stdc_ext
+ return_type: unsigned int
+ arguments:
+ - type: unsigned int
+ - type: unsigned fract
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: diviulr
+ standards:
+ - stdc_ext
+ return_type: unsigned long int
+ arguments:
+ - type: unsigned long int
+ - type: unsigned long fract
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: diviuk
+ standards:
+ - stdc_ext
+ return_type: unsigned int
+ arguments:
+ - type: unsigned int
+ - type: unsigned accum
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
+ - name: diviulk
+ standards:
+ - stdc_ext
+ return_type: unsigned long int
+ arguments:
+ - type: unsigned long int
+ - type: unsigned long accum
+ guard: LIBC_COMPILER_HAS_FIXED_POINT
diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
index f7b48b375cdba..b7121407e0307 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -102,7 +102,7 @@ foreach(suffix IN ITEMS r)
)
endforeach()
-foreach(suffix IN ITEMS r)
+foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
add_entrypoint_object(
divi${suffix}
HDRS
diff --git a/libc/src/stdfix/divik.cpp b/libc/src/stdfix/divik.cpp
new file mode 100644
index 0000000000000..549c091bca617
--- /dev/null
+++ b/libc/src/stdfix/divik.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of divik 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 "divik.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, divik, (int n, accum d)) {
+ return fixed_point::divifx<int, accum>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/divik.h b/libc/src/stdfix/divik.h
new file mode 100644
index 0000000000000..3ab530a018026
--- /dev/null
+++ b/libc/src/stdfix/divik.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for divik ------------------------*- 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_DIVIK_H
+#define LLVM_LIBC_SRC_STDFIX_DIVIK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int divik(int n, accum d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVIK_H
diff --git a/libc/src/stdfix/divilk.cpp b/libc/src/stdfix/divilk.cpp
new file mode 100644
index 0000000000000..50a85c5f0ee29
--- /dev/null
+++ b/libc/src/stdfix/divilk.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of divilk 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 "divilk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long int, divilk, (long int n, long accum d)) {
+ return fixed_point::divifx<long int, long accum>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/divilk.h b/libc/src/stdfix/divilk.h
new file mode 100644
index 0000000000000..e1ddf9b03ae67
--- /dev/null
+++ b/libc/src/stdfix/divilk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for divilk ------------------------*- 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_DIVILK_H
+#define LLVM_LIBC_SRC_STDFIX_DIVILK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long int divilk(long int, long accum);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVILK_H
diff --git a/libc/src/stdfix/divilr.cpp b/libc/src/stdfix/divilr.cpp
new file mode 100644
index 0000000000000..174649c4fad45
--- /dev/null
+++ b/libc/src/stdfix/divilr.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of divilr 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 "divilr.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(long int, divilr, (long int n, long fract d)) {
+ return fixed_point::divifx<long int, long fract>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/divilr.h b/libc/src/stdfix/divilr.h
new file mode 100644
index 0000000000000..92a93ab484b33
--- /dev/null
+++ b/libc/src/stdfix/divilr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for divilr -----------------------*- 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_DIVILR_H
+#define LLVM_LIBC_SRC_STDFIX_DIVILR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+long int divilr(long int, long fract);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVILR_H
diff --git a/libc/src/stdfix/diviuk.cpp b/libc/src/stdfix/diviuk.cpp
new file mode 100644
index 0000000000000..9b649cfd3b812
--- /dev/null
+++ b/libc/src/stdfix/diviuk.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of diviUK 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 "diviuk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned int, diviuk, (unsigned int n, unsigned accum d)) {
+ return fixed_point::divifx<unsigned int, unsigned accum>(n, d);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/diviuk.h b/libc/src/stdfix/diviuk.h
new file mode 100644
index 0000000000000..5b3846614bf4a
--- /dev/null
+++ b/libc/src/stdfix/diviuk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for diviuk -----------------------*- 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_DIVIUK_H
+#define LLVM_LIBC_SRC_STDFIX_DIVIUK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned int diviuk(unsigned int n, unsigned accum d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVIUK_H
diff --git a/libc/src/stdfix/diviulk.cpp b/libc/src/stdfix/diviulk.cpp
new file mode 100644
index 0000000000000..79411a4b32834
--- /dev/null
+++ b/libc/src/stdfix/diviulk.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of diviULK 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 "diviulk.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned long int, diviulk,
+ (unsigned long int n, unsigned long accum d)) {
+ return fixed_point::divifx<unsigned long int, unsigned long accum>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/diviulk.h b/libc/src/stdfix/diviulk.h
new file mode 100644
index 0000000000000..21ebef2394ff2
--- /dev/null
+++ b/libc/src/stdfix/diviulk.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for diviulk ----------------------*- 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_DIVIULK_H
+#define LLVM_LIBC_SRC_STDFIX_DIVIULK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned long int diviulk(unsigned long int n, unsigned long accum d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVIULK_H
diff --git a/libc/src/stdfix/diviulr.cpp b/libc/src/stdfix/diviulr.cpp
new file mode 100644
index 0000000000000..b738eb970882b
--- /dev/null
+++ b/libc/src/stdfix/diviulr.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of diviulr 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 "diviulr.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned long int, diviulr,
+ (unsigned long int n, unsigned long fract d)) {
+ return fixed_point::divifx<unsigned long int, unsigned long fract>(n, d);
+}
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/diviulr.h b/libc/src/stdfix/diviulr.h
new file mode 100644
index 0000000000000..1bc78a81ab4b3
--- /dev/null
+++ b/libc/src/stdfix/diviulr.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for diviulr ----------------------*- 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_DIVIULR_H
+#define LLVM_LIBC_SRC_STDFIX_DIVIULR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned long int diviulr(unsigned long int n, unsigned long fract d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVIULR_H
diff --git a/libc/src/stdfix/diviur.cpp b/libc/src/stdfix/diviur.cpp
new file mode 100644
index 0000000000000..922c040ffacfd
--- /dev/null
+++ b/libc/src/stdfix/diviur.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of diviur 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 "diviur.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(unsigned int, diviur, (unsigned int n, unsigned fract d)) {
+ return fixed_point::divifx<unsigned int, unsigned fract>(n, d);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/diviur.h b/libc/src/stdfix/diviur.h
new file mode 100644
index 0000000000000..60e73a8e459f6
--- /dev/null
+++ b/libc/src/stdfix/diviur.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for diviur -----------------------*- 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_DIVIUR_H
+#define LLVM_LIBC_SRC_STDFIX_DIVIUR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+unsigned int diviur(unsigned int n, unsigned fract d);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_DIVIUR_H
diff --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt
index 3bf3051c6b85a..75a98991be18d 100644
--- a/libc/test/src/stdfix/CMakeLists.txt
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -147,7 +147,7 @@ foreach(suffix IN ITEMS r)
)
endforeach()
-foreach(suffix IN ITEMS r)
+foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
add_libc_test(
divi${suffix}_test
SUITE
diff --git a/libc/test/src/stdfix/DiviFxTest.h b/libc/test/src/stdfix/DiviFxTest.h
index c3e0b8ac038e9..7dd208927d7e8 100644
--- a/libc/test/src/stdfix/DiviFxTest.h
+++ b/libc/test/src/stdfix/DiviFxTest.h
@@ -19,7 +19,7 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<FXType>;
static constexpr FXType zero = FXRep::ZERO();
- static constexpr FXType min = FXRep::MIN();
+ static constexpr FXType max = FXRep::MAX();
static constexpr FXType one_half = FXRep::ONE_HALF();
static constexpr FXType one_fourth = FXRep::ONE_FOURTH();
@@ -28,6 +28,7 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
void testBasicNumbers(DiviFxFunc func) {
constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
+ constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
EXPECT_EQ(func(1, one_fourth), static_cast<IntType>(4));
EXPECT_EQ(func(1, one_half), static_cast<IntType>(2));
@@ -53,14 +54,38 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
EXPECT_EQ(func(-2, 3 * one_fourth), static_cast<IntType>(-2));
EXPECT_EQ(func(2, -3 * one_fourth), static_cast<IntType>(-2));
} else {
- // min of unsigned type = 0
- EXPECT_EQ(func(min, one_half), static_cast<IntType>(0));
- EXPECT_EQ(func(min, one_fourth), static_cast<IntType>(0));
+ EXPECT_EQ(func(0, one_half), static_cast<IntType>(0));
+ EXPECT_EQ(func(0, one_fourth), static_cast<IntType>(0));
+ }
+
+ if constexpr (has_integral) {
+ // only run these tests for accum types that can represent the operands
+ // below
+ constexpr FXType largest_positive = static_cast<FXType>(4);
+
+ if constexpr (max >= largest_positive) {
+ EXPECT_EQ(func(3, 2.5), static_cast<IntType>(1));
+ EXPECT_EQ(func(2, 3.5), static_cast<IntType>(0));
+ EXPECT_EQ(func(3, 1.5), static_cast<IntType>(2));
+ EXPECT_EQ(func(4, 2.0), static_cast<IntType>(2));
+
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(2, -3.5), static_cast<IntType>(0));
+ EXPECT_EQ(func(-3, 2.5), static_cast<IntType>(-1));
+ EXPECT_EQ(func(-3, 1.5), static_cast<IntType>(-2));
+ EXPECT_EQ(func(-3, -2.5), static_cast<IntType>(1));
+ }
+ }
}
}
void testInvalidNumbers(DiviFxFunc func) {
+ constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
+
EXPECT_DEATH([func] { func(1, zero); }, WITH_SIGNAL(-1));
+ if constexpr (has_integral) {
+ EXPECT_DEATH([func] { func(2, zero); }, WITH_SIGNAL(-1));
+ }
}
};
diff --git a/libc/test/src/stdfix/divik_test.cpp b/libc/test/src/stdfix/divik_test.cpp
new file mode 100644
index 0000000000000..1287d5d1a8d48
--- /dev/null
+++ b/libc/test/src/stdfix/divik_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for divik -----------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/divik.h"
+
+LIST_DIVIFX_TESTS(k, int, accum, LIBC_NAMESPACE::divik);
diff --git a/libc/test/src/stdfix/divilk_test.cpp b/libc/test/src/stdfix/divilk_test.cpp
new file mode 100644
index 0000000000000..ebc6941139ca7
--- /dev/null
+++ b/libc/test/src/stdfix/divilk_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for divilk ----------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/divilk.h"
+
+LIST_DIVIFX_TESTS(lk, long int, long accum, LIBC_NAMESPACE::divilk);
diff --git a/libc/test/src/stdfix/divilr_test.cpp b/libc/test/src/stdfix/divilr_test.cpp
new file mode 100644
index 0000000000000..99567836f27b6
--- /dev/null
+++ b/libc/test/src/stdfix/divilr_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for divilr ----------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/divilr.h"
+
+LIST_DIVIFX_TESTS(lr, long int, long fract, LIBC_NAMESPACE::divilr);
diff --git a/libc/test/src/stdfix/divir_test.cpp b/libc/test/src/stdfix/divir_test.cpp
index 97f8dab63afba..e8b055561014b 100644
--- a/libc/test/src/stdfix/divir_test.cpp
+++ b/libc/test/src/stdfix/divir_test.cpp
@@ -8,7 +8,7 @@
#include "DiviFxTest.h"
-#include "llvm-libc-macros/stdfix-macros.h" // fract
+#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/divir.h"
LIST_DIVIFX_TESTS(r, int, fract, LIBC_NAMESPACE::divir);
diff --git a/libc/test/src/stdfix/diviuk_test.cpp b/libc/test/src/stdfix/diviuk_test.cpp
new file mode 100644
index 0000000000000..a7d632a661502
--- /dev/null
+++ b/libc/test/src/stdfix/diviuk_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for diviuk ----------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/diviuk.h"
+
+LIST_DIVIFX_TESTS(uk, unsigned int, unsigned accum, LIBC_NAMESPACE::diviuk);
diff --git a/libc/test/src/stdfix/diviulk_test.cpp b/libc/test/src/stdfix/diviulk_test.cpp
new file mode 100644
index 0000000000000..4709e5728fe32
--- /dev/null
+++ b/libc/test/src/stdfix/diviulk_test.cpp
@@ -0,0 +1,15 @@
+//===-- Unittests for diviulk ---------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/diviulk.h"
+
+LIST_DIVIFX_TESTS(ulk, unsigned long int, unsigned long accum,
+ LIBC_NAMESPACE::diviulk);
diff --git a/libc/test/src/stdfix/diviulr_test.cpp b/libc/test/src/stdfix/diviulr_test.cpp
new file mode 100644
index 0000000000000..48cc1f288c919
--- /dev/null
+++ b/libc/test/src/stdfix/diviulr_test.cpp
@@ -0,0 +1,15 @@
+//===-- Unittests for diviulr ---------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/diviulr.h"
+
+LIST_DIVIFX_TESTS(ulr, unsigned long int, unsigned long fract,
+ LIBC_NAMESPACE::diviulr);
diff --git a/libc/test/src/stdfix/diviur_test.cpp b/libc/test/src/stdfix/diviur_test.cpp
new file mode 100644
index 0000000000000..6fd1c17d3cd10
--- /dev/null
+++ b/libc/test/src/stdfix/diviur_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for diviur ----------------------------------------------===//
+//
+// 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 "DiviFxTest.h"
+
+#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/stdfix/diviur.h"
+
+LIST_DIVIFX_TESTS(ur, unsigned int, unsigned fract, LIBC_NAMESPACE::diviur);
>From ff62827a99520b42eaf0af582118e25a4d168c68 Mon Sep 17 00:00:00 2001
From: sohail <sohailraj.satapathy at gmail.com>
Date: Sat, 27 Jun 2026 20:25:22 +0530
Subject: [PATCH 3/7] fix formatting
Co-authored-by: Zorojuro <sawantsukumar at gmail.com>
---
libc/src/stdfix/diviuk.cpp | 1 +
libc/src/stdfix/diviulr.cpp | 1 +
2 files changed, 2 insertions(+)
diff --git a/libc/src/stdfix/diviuk.cpp b/libc/src/stdfix/diviuk.cpp
index 9b649cfd3b812..b77de93f9c3d8 100644
--- a/libc/src/stdfix/diviuk.cpp
+++ b/libc/src/stdfix/diviuk.cpp
@@ -17,4 +17,5 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned int, diviuk, (unsigned int n, unsigned accum d)) {
return fixed_point::divifx<unsigned int, unsigned accum>(n, d);
}
+
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/diviulr.cpp b/libc/src/stdfix/diviulr.cpp
index b738eb970882b..a5e85a7b2d8f1 100644
--- a/libc/src/stdfix/diviulr.cpp
+++ b/libc/src/stdfix/diviulr.cpp
@@ -18,4 +18,5 @@ LLVM_LIBC_FUNCTION(unsigned long int, diviulr,
(unsigned long int n, unsigned long fract d)) {
return fixed_point::divifx<unsigned long int, unsigned long fract>(n, d);
}
+
} // namespace LIBC_NAMESPACE_DECL
>From 3c4a557fbbb5cd3e5923302ca09544ab9fa39f30 Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Wed, 1 Jul 2026 09:07:24 +0530
Subject: [PATCH 4/7] [libc][stdfix] add and use FXRep::ONE_EIGHTH for divifx
tests
---
libc/src/__support/fixed_point/fx_rep.h | 12 ++++++++++++
libc/test/src/stdfix/DiviFxTest.h | 5 +++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/libc/src/__support/fixed_point/fx_rep.h b/libc/src/__support/fixed_point/fx_rep.h
index e68be57dedf25..bdd68e54e2e77 100644
--- a/libc/src/__support/fixed_point/fx_rep.h
+++ b/libc/src/__support/fixed_point/fx_rep.h
@@ -51,6 +51,7 @@ template <> struct FXRep<short fract> {
LIBC_INLINE static constexpr Type EPS() { return SFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5HR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25HR; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125HR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@@ -71,6 +72,7 @@ template <> struct FXRep<unsigned short fract> {
LIBC_INLINE static constexpr Type EPS() { return USFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UHR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UHR; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UHR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@@ -91,6 +93,7 @@ template <> struct FXRep<fract> {
LIBC_INLINE static constexpr Type EPS() { return FRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5R; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25R; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125R; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@@ -111,6 +114,7 @@ template <> struct FXRep<unsigned fract> {
LIBC_INLINE static constexpr Type EPS() { return UFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UR; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@@ -131,6 +135,7 @@ template <> struct FXRep<long fract> {
LIBC_INLINE static constexpr Type EPS() { return LFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5LR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25LR; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125LR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@@ -151,6 +156,7 @@ template <> struct FXRep<unsigned long fract> {
LIBC_INLINE static constexpr Type EPS() { return ULFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5ULR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25ULR; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125ULR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@@ -171,6 +177,7 @@ template <> struct FXRep<short accum> {
LIBC_INLINE static constexpr Type EPS() { return SACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5HK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25HK; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125HK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@@ -191,6 +198,7 @@ template <> struct FXRep<unsigned short accum> {
LIBC_INLINE static constexpr Type EPS() { return USACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UHK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UHK; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UHK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@@ -211,6 +219,7 @@ template <> struct FXRep<accum> {
LIBC_INLINE static constexpr Type EPS() { return ACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5K; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25K; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125K; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@@ -231,6 +240,7 @@ template <> struct FXRep<unsigned accum> {
LIBC_INLINE static constexpr Type EPS() { return UACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UK; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@@ -251,6 +261,7 @@ template <> struct FXRep<long accum> {
LIBC_INLINE static constexpr Type EPS() { return LACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5LK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25LK; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125LK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@@ -271,6 +282,7 @@ template <> struct FXRep<unsigned long accum> {
LIBC_INLINE static constexpr Type EPS() { return ULACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5ULK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25ULK; }
+ LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125ULK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
diff --git a/libc/test/src/stdfix/DiviFxTest.h b/libc/test/src/stdfix/DiviFxTest.h
index 7dd208927d7e8..5bc64abdb56b8 100644
--- a/libc/test/src/stdfix/DiviFxTest.h
+++ b/libc/test/src/stdfix/DiviFxTest.h
@@ -22,6 +22,7 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
static constexpr FXType max = FXRep::MAX();
static constexpr FXType one_half = FXRep::ONE_HALF();
static constexpr FXType one_fourth = FXRep::ONE_FOURTH();
+ static constexpr FXType one_eighth = FXRep::ONE_EIGHTH();
public:
typedef IntType (*DiviFxFunc)(IntType, FXType);
@@ -32,10 +33,10 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
EXPECT_EQ(func(1, one_fourth), static_cast<IntType>(4));
EXPECT_EQ(func(1, one_half), static_cast<IntType>(2));
- EXPECT_EQ(func(1, 0.125r), static_cast<IntType>(8));
+ EXPECT_EQ(func(1, one_eighth), static_cast<IntType>(8));
EXPECT_EQ(func(2, one_fourth), static_cast<IntType>(8));
EXPECT_EQ(func(2, one_half), static_cast<IntType>(4));
- EXPECT_EQ(func(2, 0.125r), static_cast<IntType>(16));
+ EXPECT_EQ(func(2, one_eighth), static_cast<IntType>(16));
// verify rounding towards 0
EXPECT_EQ(func(1, 3 * one_fourth), static_cast<IntType>(1));
>From a7aa0624b4ea89aba99b84fe289e754b45d33add Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Wed, 1 Jul 2026 09:37:53 +0530
Subject: [PATCH 5/7] cleanup comments
---
libc/src/__support/fixed_point/fx_bits.h | 14 ++++----------
libc/test/src/stdfix/DiviFxTest.h | 11 +++++------
2 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index 8622040e2215e..7c297d01401c6 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -335,10 +335,9 @@ template <typename XType> LIBC_INLINE constexpr XType divi(int n, int d) {
}
}
-// divide an integer operand by a fixed-point operand and return the
-// mathematically exact result as an IntType rounded towards 0. assumes
-// signedness of IntType matches the signedness of FXType. all divifx variants
-// satisfy this requirement.
+// Divide an integer operand by a fixed-point operand and return the
+// mathematically exact result as an IntType rounded towards 0. Assumes
+// signedness of IntType matches the signedness of FXType.
template <typename IntType, typename FXType>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<FXType>, IntType>
divifx(IntType n, FXType d) {
@@ -349,30 +348,25 @@ divifx(IntType n, FXType d) {
static_assert(cpp::is_signed_v<IntType> == (FXRep::SIGN_LEN > 0),
"IntType and FXType must have matching signedness");
- // UB if denominator is 0
+ // UB if denominator is 0.
LIBC_CRASH_ON_VALUE(d, FXRep::ZERO());
if (LIBC_UNLIKELY(n == 0)) {
return static_cast<IntType>(0);
}
- // get integer representation of denominator
CompType d_comp = static_cast<CompType>(FXBits(d).get_bits());
constexpr int F = FXRep::FRACTION_LEN;
- // calculating the required number of bits to represent n*2^F without
- // overflowing
constexpr int INTERMEDIATE_BITS =
sizeof(IntType) * 8 - cpp::is_signed_v<IntType> + F;
- // use 64 or 128 bit intermediates depending on INTERMEDIATE_BITS
using WideType = cpp::conditional_t<
cpp::is_signed_v<IntType>,
cpp::conditional_t<INTERMEDIATE_BITS <= 64, int64_t, Int128>,
cpp::conditional_t<INTERMEDIATE_BITS <= 64, uint64_t, UInt128>>;
- // (n*2^F/d)
WideType scaled_n = static_cast<WideType>(n) << F;
WideType result = scaled_n / static_cast<WideType>(d_comp);
diff --git a/libc/test/src/stdfix/DiviFxTest.h b/libc/test/src/stdfix/DiviFxTest.h
index 5bc64abdb56b8..a0def35d57cc7 100644
--- a/libc/test/src/stdfix/DiviFxTest.h
+++ b/libc/test/src/stdfix/DiviFxTest.h
@@ -38,7 +38,7 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
EXPECT_EQ(func(2, one_half), static_cast<IntType>(4));
EXPECT_EQ(func(2, one_eighth), static_cast<IntType>(16));
- // verify rounding towards 0
+ // Verify rounding towards 0.
EXPECT_EQ(func(1, 3 * one_fourth), static_cast<IntType>(1));
EXPECT_EQ(func(2, 3 * one_fourth), static_cast<IntType>(2));
@@ -49,7 +49,7 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
EXPECT_EQ(func(-2, one_fourth), static_cast<IntType>(-8));
EXPECT_EQ(func(2, -one_fourth), static_cast<IntType>(-8));
- // verify rounding towards 0
+ // Verify rounding towards 0.
EXPECT_EQ(func(-1, 3 * one_fourth), static_cast<IntType>(-1));
EXPECT_EQ(func(1, -3 * one_fourth), static_cast<IntType>(-1));
EXPECT_EQ(func(-2, 3 * one_fourth), static_cast<IntType>(-2));
@@ -60,11 +60,10 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
}
if constexpr (has_integral) {
- // only run these tests for accum types that can represent the operands
- // below
- constexpr FXType largest_positive = static_cast<FXType>(4);
+ // Only run these tests for accum types that can represent these operands.
+ constexpr FXType max_test_operand = static_cast<FXType>(4);
- if constexpr (max >= largest_positive) {
+ if constexpr (max >= max_test_operand) {
EXPECT_EQ(func(3, 2.5), static_cast<IntType>(1));
EXPECT_EQ(func(2, 3.5), static_cast<IntType>(0));
EXPECT_EQ(func(3, 1.5), static_cast<IntType>(2));
>From 167d284db37bc59a18ae31209638d03eae6facbe Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Thu, 2 Jul 2026 00:31:16 +0530
Subject: [PATCH 6/7] [libc][stdfix] add edge case tests for divifx functions
also reorder some members and basic number checks for consistency.
---
libc/test/src/stdfix/DiviFxTest.h | 83 +++++++++++++++++++++++++++----
1 file changed, 74 insertions(+), 9 deletions(-)
diff --git a/libc/test/src/stdfix/DiviFxTest.h b/libc/test/src/stdfix/DiviFxTest.h
index a0def35d57cc7..8d9299705d186 100644
--- a/libc/test/src/stdfix/DiviFxTest.h
+++ b/libc/test/src/stdfix/DiviFxTest.h
@@ -10,33 +10,42 @@
#include "hdr/signal_macros.h"
#include "llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/fixed_point/fx_rep.h"
+namespace cpp = LIBC_NAMESPACE::cpp;
+
template <typename IntType, typename FXType>
class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<FXType>;
- static constexpr FXType zero = FXRep::ZERO();
static constexpr FXType max = FXRep::MAX();
+ static constexpr FXType min = FXRep::MIN();
+ static constexpr FXType zero = FXRep::ZERO();
+ static constexpr FXType epsilon = FXRep::EPS();
static constexpr FXType one_half = FXRep::ONE_HALF();
static constexpr FXType one_fourth = FXRep::ONE_FOURTH();
static constexpr FXType one_eighth = FXRep::ONE_EIGHTH();
+ static constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
+ static constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
+
public:
typedef IntType (*DiviFxFunc)(IntType, FXType);
void testBasicNumbers(DiviFxFunc func) {
- constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
- constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
+ EXPECT_EQ(func(0, one_eighth), static_cast<IntType>(0));
+ EXPECT_EQ(func(0, one_fourth), static_cast<IntType>(0));
+ EXPECT_EQ(func(0, one_half), static_cast<IntType>(0));
+ EXPECT_EQ(func(1, one_eighth), static_cast<IntType>(8));
EXPECT_EQ(func(1, one_fourth), static_cast<IntType>(4));
EXPECT_EQ(func(1, one_half), static_cast<IntType>(2));
- EXPECT_EQ(func(1, one_eighth), static_cast<IntType>(8));
+ EXPECT_EQ(func(2, one_eighth), static_cast<IntType>(16));
EXPECT_EQ(func(2, one_fourth), static_cast<IntType>(8));
EXPECT_EQ(func(2, one_half), static_cast<IntType>(4));
- EXPECT_EQ(func(2, one_eighth), static_cast<IntType>(16));
// Verify rounding towards 0.
EXPECT_EQ(func(1, 3 * one_fourth), static_cast<IntType>(1));
@@ -54,12 +63,18 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
EXPECT_EQ(func(1, -3 * one_fourth), static_cast<IntType>(-1));
EXPECT_EQ(func(-2, 3 * one_fourth), static_cast<IntType>(-2));
EXPECT_EQ(func(2, -3 * one_fourth), static_cast<IntType>(-2));
- } else {
- EXPECT_EQ(func(0, one_half), static_cast<IntType>(0));
- EXPECT_EQ(func(0, one_fourth), static_cast<IntType>(0));
+
+ EXPECT_EQ(func(1, static_cast<FXType>(-1)), static_cast<IntType>(-1));
+ EXPECT_EQ(func(-1, static_cast<FXType>(-1)), static_cast<IntType>(1));
}
if constexpr (has_integral) {
+ EXPECT_EQ(func(1, static_cast<FXType>(1)), static_cast<IntType>(1));
+
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(-1, static_cast<FXType>(1)), static_cast<IntType>(-1));
+ }
+
// Only run these tests for accum types that can represent these operands.
constexpr FXType max_test_operand = static_cast<FXType>(4);
@@ -79,8 +94,56 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
}
}
+ void testEdgeCases(DiviFxFunc func) {
+
+ constexpr IntType int_max = cpp::numeric_limits<IntType>::max();
+
+ if constexpr (has_integral) {
+ EXPECT_EQ(func(int_max, static_cast<FXType>(1)), int_max);
+ }
+
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(int_max, static_cast<FXType>(-1)), -int_max);
+ }
+
+ // Only valid when integral bits (excluding sign) exceed fraction bits.
+ // Otherwise 1<<FRACTION_LEN may not fit in IntType.
+ if constexpr ((FXRep::INTEGRAL_LEN) > FXRep::FRACTION_LEN) {
+ constexpr IntType epsilon_result = static_cast<IntType>(1)
+ << FXRep::FRACTION_LEN;
+ EXPECT_EQ(func(1, epsilon), epsilon_result);
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(1, -epsilon), -epsilon_result);
+ EXPECT_EQ(func(-1, epsilon), -epsilon_result);
+ EXPECT_EQ(func(-1, -epsilon), epsilon_result);
+ }
+ }
+
+ if constexpr (has_integral) {
+ constexpr IntType largest_positive =
+ ((static_cast<IntType>(1) << FXRep::INTEGRAL_LEN) - 1);
+ EXPECT_EQ(func(largest_positive, static_cast<FXType>(largest_positive)),
+ static_cast<IntType>(1));
+ }
+
+ if constexpr (!has_integral) {
+ EXPECT_EQ(func(1, max), static_cast<IntType>(1));
+
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(1, min), static_cast<IntType>(-1));
+ }
+ }
+
+ if constexpr (has_integral) {
+ EXPECT_EQ(func(1, max), static_cast<IntType>(0));
+
+ if constexpr (is_signed) {
+ EXPECT_EQ(func(1, min), static_cast<IntType>(0));
+ }
+ }
+ }
+
void testInvalidNumbers(DiviFxFunc func) {
- constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
EXPECT_DEATH([func] { func(1, zero); }, WITH_SIGNAL(-1));
if constexpr (has_integral) {
@@ -96,10 +159,12 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
testInvalidNumbers(&func); \
} \
TEST_F(LlvmLibcDivi##Name##Test, BasicNumbers) { testBasicNumbers(&func); } \
+ TEST_F(LlvmLibcDivi##Name##Test, EdgeCases) { testEdgeCases(&func); } \
static_assert(true, "Require semicolon.")
#else
#define LIST_DIVIFX_TESTS(Name, IntType, FXType, func) \
using LlvmLibcDivi##Name##Test = DiviFxTest<IntType, FXType>; \
TEST_F(LlvmLibcDivi##Name##Test, BasicNumbers) { testBasicNumbers(&func); } \
+ TEST_F(LlvmLibcDivi##Name##Test, EdgeCases) { testEdgeCases(&func); } \
static_assert(true, "Require semicolon.")
#endif // LIBC_ADD_NULL_CHECKS
>From 634eea8866d5641d31097373eb389b159c2c142e Mon Sep 17 00:00:00 2001
From: sohail103 <sohailraj.satapathy at gmail.com>
Date: Wed, 8 Jul 2026 15:45:22 +0530
Subject: [PATCH 7/7] [libc][stdfix] add test for large power of two
---
libc/test/src/stdfix/DiviFxTest.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libc/test/src/stdfix/DiviFxTest.h b/libc/test/src/stdfix/DiviFxTest.h
index 8d9299705d186..06c4868367858 100644
--- a/libc/test/src/stdfix/DiviFxTest.h
+++ b/libc/test/src/stdfix/DiviFxTest.h
@@ -124,6 +124,12 @@ class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
((static_cast<IntType>(1) << FXRep::INTEGRAL_LEN) - 1);
EXPECT_EQ(func(largest_positive, static_cast<FXType>(largest_positive)),
static_cast<IntType>(1));
+
+ constexpr IntType largest_power_of_two = static_cast<IntType>(1)
+ << (FXRep::INTEGRAL_LEN - 1);
+ EXPECT_EQ(
+ func(largest_power_of_two, static_cast<FXType>(largest_power_of_two)),
+ static_cast<IntType>(1));
}
if constexpr (!has_integral) {
More information about the libc-commits
mailing list