[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