[libc-commits] [libc] [llvm] [libc][NFC] Split out `is_{odd_}integer` utility (PR #234288)

Connector Switch via libc-commits libc-commits at lists.llvm.org
Wed Oct 21 10:50:15 PDT 2026


https://github.com/c8ef updated https://github.com/llvm/llvm-project/pull/234288

>From cfd54e79772b98517aa0936051278c250cacc8f8 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Thu, 22 Oct 2026 01:39:04 +0800
Subject: [PATCH 1/2] [libc][NFC] Split out is_{odd_}integer utility

---
 libc/src/__support/FPUtil/CMakeLists.txt      |  11 ++
 libc/src/__support/FPUtil/is_integer.h        |  62 ++++++
 libc/src/__support/math/CMakeLists.txt        |   6 +-
 libc/src/__support/math/gamma_util.h          |  14 --
 libc/src/__support/math/lgammaf.h             |   3 +-
 libc/src/__support/math/lgammaf16.h           |   3 +-
 libc/src/__support/math/pow.h                 |   3 +-
 libc/src/__support/math/pow_utils.h           |  43 +---
 libc/src/__support/math/powf_utils.h          |  44 +----
 libc/test/src/__support/FPUtil/CMakeLists.txt |  13 ++
 .../src/__support/FPUtil/is_integer_test.cpp  | 185 ++++++++++++++++++
 .../llvm-project-overlay/libc/BUILD.bazel     |  15 ++
 .../test/src/__support/FPUtil/BUILD.bazel     |  12 ++
 13 files changed, 322 insertions(+), 92 deletions(-)
 create mode 100644 libc/src/__support/FPUtil/is_integer.h
 create mode 100644 libc/test/src/__support/FPUtil/is_integer_test.cpp

diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index bb50616d6a28ca..97b907cb0e5844 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -258,6 +258,17 @@ add_header_library(
     libc.src.__support.uint128
 )
 
+add_header_library(
+  is_integer
+  HDRS
+    is_integer.h
+  DEPENDS
+    .fp_bits
+    libc.src.__support.CPP.bit
+    libc.src.__support.macros.attributes
+    libc.src.__support.macros.config
+)
+
 add_header_library(
   manipulation_functions
   HDRS
diff --git a/libc/src/__support/FPUtil/is_integer.h b/libc/src/__support/FPUtil/is_integer.h
new file mode 100644
index 00000000000000..7864ee9011239d
--- /dev/null
+++ b/libc/src/__support/FPUtil/is_integer.h
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Floating-point integer check functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_IS_INTEGER_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_IS_INTEGER_H
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+// These helpers require finite inputs.
+
+// Check if x is an odd integer: its lowest set significand bit must be at the
+// unit position, so x_e + lsb == UNIT_EXPONENT.
+template <typename T> LIBC_INLINE constexpr bool is_odd_integer(T x) {
+  using FPBits = FPBits<T>;
+  using StorageType = typename FPBits::StorageType;
+  FPBits xbits(x);
+  StorageType x_u = xbits.uintval();
+  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
+  unsigned lsb = static_cast<unsigned>(
+      cpp::countr_zero(static_cast<StorageType>(x_u | FPBits::EXP_MASK)));
+  constexpr unsigned UNIT_EXPONENT =
+      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
+  return x_e + lsb == UNIT_EXPONENT;
+}
+
+// Check if x is an integer: its lowest set significand bit must be at or above
+// the unit position, so x_e + lsb >= UNIT_EXPONENT.
+template <typename T> LIBC_INLINE constexpr bool is_integer(T x) {
+  using FPBits = FPBits<T>;
+  using StorageType = typename FPBits::StorageType;
+  FPBits xbits(x);
+  if (xbits.is_zero())
+    return true;
+  StorageType x_u = xbits.uintval();
+  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
+  unsigned lsb = static_cast<unsigned>(
+      cpp::countr_zero(static_cast<StorageType>(x_u | FPBits::EXP_MASK)));
+  constexpr unsigned UNIT_EXPONENT =
+      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
+  return x_e + lsb >= UNIT_EXPONENT;
+}
+
+} // namespace fputil
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_IS_INTEGER_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 58f0730cba5756..31b7356667e557 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3918,9 +3918,9 @@ add_header_library(
   HDRS
     gamma_util.h
   DEPENDS
-    libc.src.__support.CPP.bit
     libc.src.__support.FPUtil.fp_bits
     libc.src.__support.FPUtil.multiply_add
+    libc.src.__support.macros.attributes
     libc.src.__support.macros.config
 )
 
@@ -4095,6 +4095,7 @@ add_header_library(
     libc.src.__support.FPUtil.except_value_utils
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.is_integer
     libc.src.__support.FPUtil.multiply_add
     libc.src.__support.FPUtil.nearest_integer_operations
     libc.src.__support.FPUtil.polyeval
@@ -4113,6 +4114,7 @@ add_header_library(
     libc.src.__support.FPUtil.cast
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.is_integer
     libc.src.__support.FPUtil.multiply_add
     libc.src.__support.FPUtil.nearest_integer_operations
     libc.src.__support.FPUtil.polyeval
@@ -5539,6 +5541,7 @@ add_header_library(
     libc.src.__support.FPUtil.dyadic_float
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.is_integer
     libc.src.__support.FPUtil.multiply_add
     libc.src.__support.FPUtil.nearest_integer
     libc.src.__support.FPUtil.polyeval
@@ -5567,6 +5570,7 @@ add_header_library(
     libc.src.__support.FPUtil.double_double
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.is_integer
     libc.src.__support.FPUtil.nearest_integer
     libc.src.__support.FPUtil.rounding_mode
     libc.src.__support.FPUtil.sqrt
diff --git a/libc/src/__support/math/gamma_util.h b/libc/src/__support/math/gamma_util.h
index 007786368b7d52..78ef9c8a330e30 100644
--- a/libc/src/__support/math/gamma_util.h
+++ b/libc/src/__support/math/gamma_util.h
@@ -9,7 +9,6 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_GAMMA_UTIL_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_GAMMA_UTIL_H
 
-#include "src/__support/CPP/bit.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/multiply_add.h"
 #include "src/__support/macros/attributes.h"
@@ -21,19 +20,6 @@ namespace math {
 
 namespace gamma_internal {
 
-template <typename T> LIBC_INLINE constexpr bool is_integer(T x) {
-  using FPBits = fputil::FPBits<T>;
-  using StorageType = typename FPBits::StorageType;
-  FPBits xbits(x);
-  StorageType x_u = xbits.uintval();
-  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
-  unsigned lsb = static_cast<unsigned>(
-      cpp::countr_zero(static_cast<StorageType>(x_u | FPBits::EXP_MASK)));
-  constexpr unsigned UNIT_EXPONENT =
-      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
-  return x_e + lsb >= UNIT_EXPONENT;
-}
-
 // sin(pi*x) for x in (0, 1), written as (0.25 - u^2) * P(u^2) where u = x-0.5.
 // Coefficients for P are a degree-7 polynomial in u^2
 // approximating sin(pi*(u+0.5)) / (pi*(0.25-u^2))
diff --git a/libc/src/__support/math/lgammaf.h b/libc/src/__support/math/lgammaf.h
index d5858df303d6ef..dbccad013273c9 100644
--- a/libc/src/__support/math/lgammaf.h
+++ b/libc/src/__support/math/lgammaf.h
@@ -15,6 +15,7 @@
 #include "src/__support/FPUtil/PolyEval.h"
 #include "src/__support/FPUtil/cast.h"
 #include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/is_integer.h"
 #include "src/__support/FPUtil/multiply_add.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/optimization.h"
@@ -89,7 +90,7 @@ LIBC_INLINE float lgammaf(float x) {
   }
 
   // Negative integers and lgamma(1) = lgamma(2) = 0.
-  if (LIBC_UNLIKELY(is_integer(x))) {
+  if (LIBC_UNLIKELY(fputil::is_integer(x))) {
     if (xbits.is_neg()) {
       fputil::raise_except_if_required(FE_DIVBYZERO);
       fputil::set_errno_if_required(ERANGE);
diff --git a/libc/src/__support/math/lgammaf16.h b/libc/src/__support/math/lgammaf16.h
index 28660fe92d5adb..6dccd937890405 100644
--- a/libc/src/__support/math/lgammaf16.h
+++ b/libc/src/__support/math/lgammaf16.h
@@ -18,6 +18,7 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/FPUtil/PolyEval.h"
 #include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/is_integer.h"
 #include "src/__support/FPUtil/multiply_add.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/optimization.h"
@@ -53,7 +54,7 @@ LIBC_INLINE float16 lgammaf16(float16 x) {
     return FPBits::inf().get_val();
   }
 
-  if (LIBC_UNLIKELY(is_integer(x))) {
+  if (LIBC_UNLIKELY(fputil::is_integer(x))) {
     if (xbits.is_neg()) {
       // pole -> +Inf
       fputil::raise_except_if_required(FE_DIVBYZERO);
diff --git a/libc/src/__support/math/pow.h b/libc/src/__support/math/pow.h
index 75125d789627a2..ae2772632c9ecc 100644
--- a/libc/src/__support/math/pow.h
+++ b/libc/src/__support/math/pow.h
@@ -16,6 +16,7 @@
 
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/is_integer.h"
 #include "src/__support/FPUtil/multiply_add.h"
 #include "src/__support/FPUtil/nearest_integer.h"
 #include "src/__support/common.h"
@@ -456,7 +457,7 @@ LIBC_INLINE double pow(double x, double y) {
       //    representable power of 2 in double precision).
       if (LIBC_UNLIKELY(x_mant == 0)) {
         double ex_y = e_x * y;
-        if (ex_y >= -1074.0 && pow_internal::is_integer(ex_y))
+        if (ex_y >= -1074.0 && fputil::is_integer(ex_y))
           return res;
       } else if (LIBC_UNLIKELY(y > 0.0 && y <= 35.0)) {
         // 2. If x is not a power of 2, exact results in double precision can
diff --git a/libc/src/__support/math/pow_utils.h b/libc/src/__support/math/pow_utils.h
index 305dbc67590be8..2c78e42f67d5c3 100644
--- a/libc/src/__support/math/pow_utils.h
+++ b/libc/src/__support/math/pow_utils.h
@@ -21,6 +21,7 @@
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/is_integer.h"
 #include "src/__support/FPUtil/nearest_integer.h"
 #include "src/__support/FPUtil/rounding_mode.h"
 #include "src/__support/FPUtil/sqrt.h"
@@ -182,38 +183,6 @@ LIBC_INLINE_VAR constexpr DoubleDouble LOG2_R_DD[128] = {
     {0.0, 1.0},
 };
 
-// Check if x is an odd integer: the lowest set bit must be at the unit
-// position:
-//   x_e + lsb == UNIT_EXPONENT.
-LIBC_INLINE bool is_odd_integer(double x) {
-  using FPBits = fputil::FPBits<double>;
-  FPBits xbits(x);
-  uint64_t x_u = xbits.uintval();
-  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
-  unsigned lsb =
-      static_cast<unsigned>(cpp::countr_zero(x_u | FPBits::EXP_MASK));
-  constexpr unsigned UNIT_EXPONENT =
-      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
-  return (x_e + lsb == UNIT_EXPONENT);
-}
-
-// Check if x is an integer: the lowest set bit must be at or above the unit
-// position:
-//   x_e + lsb >= UNIT_EXPONENT.
-LIBC_INLINE bool is_integer(double x) {
-  if (x == 0.0)
-    return true;
-  using FPBits = fputil::FPBits<double>;
-  FPBits xbits(x);
-  uint64_t x_u = xbits.uintval();
-  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
-  unsigned lsb =
-      static_cast<unsigned>(cpp::countr_zero(x_u | FPBits::EXP_MASK));
-  constexpr unsigned UNIT_EXPONENT =
-      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
-  return (x_e + lsb >= UNIT_EXPONENT);
-}
-
 LIBC_INLINE double set_overflow(bool is_neg) {
   fputil::set_errno_if_required(ERANGE);
   fputil::raise_overflow_except_if_required<double>();
@@ -369,7 +338,7 @@ LIBC_ALWAYS_INLINE cpp::optional<double> check_special_inputs(double x,
         return y;
       if (y_abs.is_inf())
         return y_sign ? FPBits::inf().get_val() : 0.0;
-      bool out_is_neg = x_sign && is_odd_integer(y);
+      bool out_is_neg = x_sign && fputil::is_odd_integer(y);
       if (y_sign) {
         // pow(0, negative number) = inf
         fputil::set_errno_if_required(EDOM);
@@ -493,9 +462,9 @@ check_exceptional_cases(double &x, double &y, double &e_x, uint64_t &x_mant,
   }
 
   if (x_sign) {
-    if (is_integer(y)) {
+    if (fputil::is_integer(y)) {
       x = -x;
-      if (is_odd_integer(y)) {
+      if (fputil::is_odd_integer(y)) {
         is_neg = true;
         sign_d = -1.0;
       }
@@ -597,7 +566,7 @@ LIBC_INLINE bool is_exact_rounding_boundary(double x, double y,
   if (x_mant == 0) {
     double e = static_cast<double>(x_e);
     double ey = e * y;
-    if (is_integer(ey)) {
+    if (fputil::is_integer(ey)) {
       exact_m = 1;
       exact_exp = static_cast<int>(ey);
       return true;
@@ -629,7 +598,7 @@ LIBC_INLINE bool is_exact_rounding_boundary(double x, double y,
   if (f < 0) {
     // Non-integer exponent: y = n / 2^(-f) with -f in {1, ..., 5}.
     double ey = static_cast<double>(e) * y;
-    if (!is_integer(ey))
+    if (!fputil::is_integer(ey))
       return false;
 
     // Check if m^(2^f) is an integer by taking repeated square roots -f times.
diff --git a/libc/src/__support/math/powf_utils.h b/libc/src/__support/math/powf_utils.h
index 406ab3680f4c08..86fd6b44366c43 100644
--- a/libc/src/__support/math/powf_utils.h
+++ b/libc/src/__support/math/powf_utils.h
@@ -21,6 +21,7 @@
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/is_integer.h"
 #include "src/__support/FPUtil/nearest_integer.h"
 #include "src/__support/FPUtil/rounding_mode.h"
 #include "src/__support/FPUtil/triple_double.h"
@@ -326,38 +327,6 @@ constexpr uint32_t Y_UPPER_BOUND = 0x4ecf'f1b4;
 // 0x2f5a740d
 constexpr uint32_t Y_LOWER_BOUND = 0x2f5a'740d;
 
-// Check if x is an odd integer: the lowest set bit must be at the unit
-// position:
-//   x_e + lsb == UNIT_EXPONENT.
-LIBC_INLINE bool is_odd_integer(float x) {
-  using FPBits = fputil::FPBits<float>;
-  FPBits xbits(x);
-  uint32_t x_u = xbits.uintval();
-  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
-  unsigned lsb =
-      static_cast<unsigned>(cpp::countr_zero(x_u | FPBits::EXP_MASK));
-  constexpr unsigned UNIT_EXPONENT =
-      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
-  return (x_e + lsb == UNIT_EXPONENT);
-}
-
-// Check if x is an integer: the lowest set bit must be at or above the unit
-// position:
-//   x_e + lsb >= UNIT_EXPONENT.
-LIBC_INLINE bool is_integer(float x) {
-  if (x == 0.0f)
-    return true;
-  using FPBits = fputil::FPBits<float>;
-  FPBits xbits(x);
-  uint32_t x_u = xbits.uintval();
-  unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent());
-  unsigned lsb =
-      static_cast<unsigned>(cpp::countr_zero(x_u | FPBits::EXP_MASK));
-  constexpr unsigned UNIT_EXPONENT =
-      static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN);
-  return (x_e + lsb >= UNIT_EXPONENT);
-}
-
 LIBC_INLINE float set_overflow(Sign sign = Sign::POS) {
   fputil::set_errno_if_required(ERANGE);
   fputil::raise_overflow_except_if_required<float>();
@@ -420,7 +389,7 @@ LIBC_ALWAYS_INLINE cpp::optional<float> check_special_inputs(float x, float y) {
       return y;
     if (y_abs.is_inf())
       return y_sign ? FPBits::inf().get_val() : 0.0f;
-    bool out_is_neg = x_sign && is_odd_integer(y);
+    bool out_is_neg = x_sign && fputil::is_odd_integer(y);
     if (y_sign) {
       // pow(0, negative number) = Inf
       fputil::set_errno_if_required(EDOM);
@@ -449,8 +418,9 @@ LIBC_ALWAYS_INLINE cpp::optional<float> check_special_inputs(float x, float y) {
   uint32_t y_a = y_abs.uintval();
   if (x_abs.is_normal() && xbits.get_mantissa() == 0 && y_a > Y_LOWER_BOUND &&
       y_a < Y_UPPER_BOUND) {
-    if (!x_sign || is_integer(y)) {
-      Sign out_sign = (x_sign && is_odd_integer(y)) ? Sign::NEG : Sign::POS;
+    if (!x_sign || fputil::is_integer(y)) {
+      Sign out_sign =
+          (x_sign && fputil::is_odd_integer(y)) ? Sign::NEG : Sign::POS;
       int e_x = xbits.get_exponent();
       double ey = static_cast<double>(e_x) * static_cast<double>(y);
       double ey_int = fputil::nearest_integer(ey);
@@ -555,8 +525,8 @@ check_exceptional_cases(float &x, float &y, int &ex, SignType &sign) {
   //   in real numbers; raises FE_INVALID, sets errno to EDOM, and returns
   //   quiet NaN.
   if (x_sign) {
-    if (is_integer(y)) {
-      if (is_odd_integer(y)) {
+    if (fputil::is_integer(y)) {
+      if (fputil::is_odd_integer(y)) {
         if constexpr (sizeof(SignType) == 8)
           sign = 0x8000'0000'0000'0000ULL;
         else
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index deed4f201dd0a5..b144b52bb967c7 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -106,3 +106,16 @@ add_fp_unittest(
     libc.src.__support.FPUtil.comparison_operations
     libc.src.__support.macros.properties.types
 )
+
+add_fp_unittest(
+  is_integer_test
+  SUITE
+    libc-fputil-tests
+  SRCS
+    is_integer_test.cpp
+  DEPENDS
+    libc.src.__support.FPUtil.bfloat16
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.is_integer
+    libc.src.__support.macros.properties.types
+)
diff --git a/libc/test/src/__support/FPUtil/is_integer_test.cpp b/libc/test/src/__support/FPUtil/is_integer_test.cpp
new file mode 100644
index 00000000000000..7329c50a2b8e8e
--- /dev/null
+++ b/libc/test/src/__support/FPUtil/is_integer_test.cpp
@@ -0,0 +1,185 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for floating-point integer check functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/__support/FPUtil/is_integer.h"
+#include "src/__support/macros/properties/types.h"
+#include "test/UnitTest/FEnvSafeTest.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::fputil::BFloat16;
+using LIBC_NAMESPACE::fputil::is_integer;
+using LIBC_NAMESPACE::fputil::is_odd_integer;
+
+template <typename T>
+class IsIntegerTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+  DECLARE_SPECIAL_CONSTANTS(T)
+
+  static T get_two_pow_frac() {
+    T result = T(1.0);
+    for (int i = 0; i < FPBits::FRACTION_LEN; ++i)
+      result *= T(2.0);
+    return result;
+  }
+
+public:
+  void test_is_integer() {
+    EXPECT_TRUE(is_integer(zero));
+    EXPECT_TRUE(is_integer(neg_zero));
+
+    EXPECT_TRUE(is_integer(T(1.0)));
+    EXPECT_TRUE(is_integer(T(-1.0)));
+    EXPECT_TRUE(is_integer(T(2.0)));
+    EXPECT_TRUE(is_integer(T(-2.0)));
+    EXPECT_TRUE(is_integer(T(3.0)));
+    EXPECT_TRUE(is_integer(T(-3.0)));
+    EXPECT_TRUE(is_integer(T(10.0)));
+    EXPECT_TRUE(is_integer(T(-10.0)));
+    EXPECT_TRUE(is_integer(T(100.0)));
+    EXPECT_TRUE(is_integer(T(-100.0)));
+
+    EXPECT_FALSE(is_integer(T(0.5)));
+    EXPECT_FALSE(is_integer(T(-0.5)));
+    EXPECT_FALSE(is_integer(T(1.5)));
+    EXPECT_FALSE(is_integer(T(-1.5)));
+    EXPECT_FALSE(is_integer(T(0.25)));
+    EXPECT_FALSE(is_integer(T(-0.25)));
+    EXPECT_FALSE(is_integer(T(0.75)));
+    EXPECT_FALSE(is_integer(T(-0.75)));
+
+    EXPECT_FALSE(is_integer(min_denormal));
+    EXPECT_FALSE(is_integer(neg_min_denormal));
+    EXPECT_FALSE(is_integer(max_denormal));
+
+    T two_pow_frac = get_two_pow_frac();
+    EXPECT_TRUE(is_integer(two_pow_frac));
+    EXPECT_TRUE(is_integer(-two_pow_frac));
+
+    EXPECT_TRUE(is_integer(T(two_pow_frac - T(1.0))));
+    EXPECT_TRUE(is_integer(T(-(two_pow_frac - T(1.0)))));
+
+    EXPECT_TRUE(is_integer(T(two_pow_frac + T(1.0))));
+    EXPECT_TRUE(is_integer(T(-(two_pow_frac + T(1.0)))));
+
+    EXPECT_FALSE(is_integer(T(two_pow_frac - T(1.0) + T(0.5))));
+    EXPECT_FALSE(is_integer(T(-(two_pow_frac - T(1.0) + T(0.5)))));
+  }
+
+  void test_is_odd_integer() {
+    EXPECT_FALSE(is_odd_integer(zero));
+    EXPECT_FALSE(is_odd_integer(neg_zero));
+
+    EXPECT_TRUE(is_odd_integer(T(1.0)));
+    EXPECT_TRUE(is_odd_integer(T(-1.0)));
+    EXPECT_FALSE(is_odd_integer(T(2.0)));
+    EXPECT_FALSE(is_odd_integer(T(-2.0)));
+    EXPECT_TRUE(is_odd_integer(T(3.0)));
+    EXPECT_TRUE(is_odd_integer(T(-3.0)));
+    EXPECT_FALSE(is_odd_integer(T(4.0)));
+    EXPECT_FALSE(is_odd_integer(T(-4.0)));
+    EXPECT_TRUE(is_odd_integer(T(5.0)));
+    EXPECT_TRUE(is_odd_integer(T(-5.0)));
+    EXPECT_FALSE(is_odd_integer(T(10.0)));
+    EXPECT_FALSE(is_odd_integer(T(-10.0)));
+    EXPECT_TRUE(is_odd_integer(T(11.0)));
+    EXPECT_TRUE(is_odd_integer(T(-11.0)));
+
+    EXPECT_FALSE(is_odd_integer(T(0.5)));
+    EXPECT_FALSE(is_odd_integer(T(-0.5)));
+    EXPECT_FALSE(is_odd_integer(T(1.5)));
+    EXPECT_FALSE(is_odd_integer(T(-1.5)));
+    EXPECT_FALSE(is_odd_integer(T(2.5)));
+    EXPECT_FALSE(is_odd_integer(T(-2.5)));
+
+    EXPECT_FALSE(is_odd_integer(min_denormal));
+    EXPECT_FALSE(is_odd_integer(neg_min_denormal));
+    EXPECT_FALSE(is_odd_integer(max_denormal));
+
+    T two_pow_frac = get_two_pow_frac();
+    EXPECT_FALSE(is_odd_integer(two_pow_frac));
+    EXPECT_FALSE(is_odd_integer(-two_pow_frac));
+
+    EXPECT_TRUE(is_odd_integer(T(two_pow_frac - T(1.0))));
+    EXPECT_TRUE(is_odd_integer(T(-(two_pow_frac - T(1.0)))));
+
+    EXPECT_TRUE(is_odd_integer(T(two_pow_frac + T(1.0))));
+    EXPECT_TRUE(is_odd_integer(T(-(two_pow_frac + T(1.0)))));
+
+    EXPECT_FALSE(is_odd_integer(T(two_pow_frac + T(2.0))));
+    EXPECT_FALSE(is_odd_integer(T(-(two_pow_frac + T(2.0)))));
+
+    T two_pow_frac_plus_1 = two_pow_frac * T(2.0);
+    EXPECT_FALSE(is_odd_integer(two_pow_frac_plus_1));
+    EXPECT_FALSE(is_odd_integer(-two_pow_frac_plus_1));
+  }
+};
+
+#define TEST_IS_INTEGER(Name, Type)                                            \
+  using LlvmLibc##Name##IsIntegerTest = IsIntegerTest<Type>;                   \
+  TEST_F(LlvmLibc##Name##IsIntegerTest, IsInteger) { test_is_integer(); }      \
+  TEST_F(LlvmLibc##Name##IsIntegerTest, IsOddInteger) { test_is_odd_integer(); }
+
+TEST_IS_INTEGER(Float, float)
+TEST_IS_INTEGER(Double, double)
+TEST_IS_INTEGER(LongDouble, long double)
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+TEST_IS_INTEGER(Float16, float16)
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128
+TEST_IS_INTEGER(DFloat128, float128)
+#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128
+
+TEST_IS_INTEGER(BFloat16, BFloat16)
+
+TEST(LlvmLibcIsIntegerConstexprTest, ConstexprEval) {
+  static_assert(is_integer(0.0));
+  static_assert(is_integer(-0.0));
+  static_assert(is_integer(1.0));
+  static_assert(is_integer(-1.0));
+  static_assert(is_integer(2.0));
+  static_assert(is_integer(-2.0));
+  static_assert(!is_integer(0.5));
+  static_assert(!is_integer(-0.5));
+  static_assert(!is_integer(1.5));
+  static_assert(!is_integer(-1.5));
+
+  static_assert(!is_odd_integer(0.0));
+  static_assert(!is_odd_integer(-0.0));
+  static_assert(is_odd_integer(1.0));
+  static_assert(is_odd_integer(-1.0));
+  static_assert(!is_odd_integer(2.0));
+  static_assert(!is_odd_integer(-2.0));
+  static_assert(is_odd_integer(3.0));
+  static_assert(is_odd_integer(-3.0));
+  static_assert(!is_odd_integer(0.5));
+  static_assert(!is_odd_integer(-0.5));
+  static_assert(!is_odd_integer(1.5));
+  static_assert(!is_odd_integer(-1.5));
+
+  static_assert(is_integer(0.0f));
+  static_assert(is_integer(-0.0f));
+  static_assert(is_integer(1.0f));
+  static_assert(is_integer(-1.0f));
+  static_assert(is_integer(2.0f));
+  static_assert(!is_integer(0.5f));
+
+  static_assert(!is_odd_integer(0.0f));
+  static_assert(is_odd_integer(1.0f));
+  static_assert(!is_odd_integer(2.0f));
+  static_assert(is_odd_integer(3.0f));
+  static_assert(!is_odd_integer(0.5f));
+}
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 632ff4a16a83c9..e46b609f846012 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3470,6 +3470,17 @@ libc_support_library(
     ],
 )
 
+libc_support_library(
+    name = "__support_fputil_is_integer",
+    hdrs = ["src/__support/FPUtil/is_integer.h"],
+    deps = [
+        ":__support_cpp_bit",
+        ":__support_fputil_fp_bits",
+        ":__support_macros_attributes",
+        ":__support_macros_config",
+    ],
+)
+
 libc_support_library(
     name = "__support_fputil_manipulation_functions",
     hdrs = ["src/__support/FPUtil/ManipulationFunctions.h"],
@@ -10188,6 +10199,7 @@ libc_support_library(
         ":__support_fputil_except_value_utils",
         ":__support_fputil_fenv_impl",
         ":__support_fputil_fp_bits",
+        ":__support_fputil_is_integer",
         ":__support_fputil_multiply_add",
         ":__support_fputil_nearest_integer_operations",
         ":__support_fputil_polyeval",
@@ -10207,6 +10219,7 @@ libc_support_library(
         ":__support_fputil_cast",
         ":__support_fputil_fenv_impl",
         ":__support_fputil_fp_bits",
+        ":__support_fputil_is_integer",
         ":__support_fputil_multiply_add",
         ":__support_fputil_nearest_integer_operations",
         ":__support_fputil_polyeval",
@@ -10550,6 +10563,7 @@ libc_support_library(
         ":__support_fputil_dyadic_float",
         ":__support_fputil_fenv_impl",
         ":__support_fputil_fp_bits",
+        ":__support_fputil_is_integer",
         ":__support_fputil_multiply_add",
         ":__support_fputil_nearest_integer",
         ":__support_fputil_polyeval",
@@ -10630,6 +10644,7 @@ libc_support_library(
         ":__support_fputil_double_double",
         ":__support_fputil_fenv_impl",
         ":__support_fputil_fp_bits",
+        ":__support_fputil_is_integer",
         ":__support_fputil_nearest_integer",
         ":__support_fputil_rounding_mode",
         ":__support_fputil_sqrt",
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel
index fcaf22790bb342..5fda9b919b7f45 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel
@@ -85,3 +85,15 @@ libc_test(
         "//libc/test/UnitTest:fp_test_helpers",
     ],
 )
+
+libc_test(
+    name = "is_integer_test",
+    srcs = ["is_integer_test.cpp"],
+    deps = [
+        "//libc:__support_fputil_bfloat16",
+        "//libc:__support_fputil_fp_bits",
+        "//libc:__support_fputil_is_integer",
+        "//libc:__support_macros_properties_types",
+        "//libc/test/UnitTest:fp_test_helpers",
+    ],
+)

>From ad2382e027a1f6c24477ff5688e8e1338ca6d3f1 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Thu, 22 Oct 2026 01:49:59 +0800
Subject: [PATCH 2/2] fix bazel build for APFloat

---
 utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 1 +
 1 file changed, 1 insertion(+)

diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index e46b609f846012..eff8add831b6d2 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -5090,6 +5090,7 @@ cc_library(
         ":__support_fputil_fp_bits",
         ":__support_fputil_generic_fmod",
         ":__support_fputil_hypot",
+        ":__support_fputil_is_integer",
         ":__support_fputil_manipulation_functions",
         ":__support_fputil_multiply_add",
         ":__support_fputil_nearest_integer",



More information about the libc-commits mailing list