[libc-commits] [libc] [libc][math] Add gcc-7 to 9 compatibility for shared math. (PR #197868)

via libc-commits libc-commits at lists.llvm.org
Thu May 21 06:54:57 PDT 2026


https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/197868

>From 43e3a82521d8c1fd4b2788d7a17d6a1f68d85161 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 04:51:41 +0000
Subject: [PATCH 1/7] [libc] Support building shared tests with gcc-7, 8, 9.

- Add more fine-grained constexpr annotations.
---
 libc/src/__support/macros/attributes.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/libc/src/__support/macros/attributes.h b/libc/src/__support/macros/attributes.h
index b3e1e12889511..cffcabcd29bd3 100644
--- a/libc/src/__support/macros/attributes.h
+++ b/libc/src/__support/macros/attributes.h
@@ -48,19 +48,41 @@
 #endif // has_builtin(__builtin_bit_cast)
 #endif // LIBC_HAS_BUILTIN_BIT_CAST
 
+#if LIBC_HAS_BUILTIN_BIT_CAST
+#define LIBC_BIT_CAST_CONSTEXPR constexpr
+#define LIBC_BIT_CAST_CONSTEXPR_VAR constexpr
+#else
+#define LIBC_BIT_CAST_CONSTEXPR
+#define LIBC_BIT_CAST_CONSTEXPR_VAR const
+#endif // LIBC_HAS_BUILTIN_BIT_CAST
+
 #ifndef LIBC_HAS_CONSTANT_EVALUATION
 #define LIBC_HAS_CONSTANT_EVALUATION                                           \
   (LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED && LIBC_HAS_BUILTIN_BIT_CAST)
 #endif // LIBC_HAS_CONSTANT_EVALUATION
 
+#if LIBC_HAS_CONSTANT_EVALUATION
+#define LIBC_CONSTEXPR_DEFAULT constexpr
+#define LIBC_CONSTEXPR_VAR_DEFAULT constexpr
+#else
+#define LIBC_CONSTEXPR_DEFAULT
+#define LIBC_CONSTEXPR_VAR_DEFAULT const
+#endif // LIBC_HAS_CONSTANT_EVALUATION
+
 // TODO: Remove the macro once Clang/LLVM bump their minimum compilers' version.
 // The reason for indirection is GCC is known to fail with constexpr qualified
 // functions that doesn't produce constant expression.
+// Also, there are some circular dependency in the generic functions without
+// __builtin_func for the following functions:
+//   fputil::fma
+//   fputil::sqrt
 #if LIBC_ENABLE_CONSTEXPR && LIBC_HAS_CONSTANT_EVALUATION
 #define LIBC_USE_CONSTEXPR
 #define LIBC_CONSTEXPR constexpr
+#define LIBC_CONSTEXPR_VAR constexpr
 #else
 #define LIBC_CONSTEXPR
+#define LIBC_CONSTEXPR_VAR const
 #endif // LIBC_USE_CONSTEXPR
 
 #ifndef LIBC_HAS_BUILTIN_IS_ASSIGNABLE

>From b3002ac664ac9c8ceaf38eadb496fce8d4fbd3dc Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 04:54:06 +0000
Subject: [PATCH 2/7] Update LIBC_LOOP_(NO)UNROLL annotation compatibility.

---
 libc/src/__support/macros/optimization.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libc/src/__support/macros/optimization.h b/libc/src/__support/macros/optimization.h
index dbefd20a5cd16..a1e5766393190 100644
--- a/libc/src/__support/macros/optimization.h
+++ b/libc/src/__support/macros/optimization.h
@@ -32,8 +32,13 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) {
 #define LIBC_LOOP_NOUNROLL _Pragma("nounroll")
 #define LIBC_LOOP_UNROLL _Pragma("unroll")
 #elif defined(LIBC_COMPILER_IS_GCC)
+#if LIBC_COMPILER_GCC_VER >= 800
 #define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0")
 #define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048")
+#else
+#define LIBC_LOOP_NOUNROLL
+#define LIBC_LOOP_UNROLL
+#endif
 #elif defined(LIBC_COMPILER_IS_MSVC)
 #define LIBC_LOOP_NOUNROLL
 #define LIBC_LOOP_UNROLL

>From 52df4aabbb0d21755372dfc52ffbb1faee47b8a9 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 04:56:10 +0000
Subject: [PATCH 3/7] Apply fine-grained constexpr annotations to
 src/__support/FPUtil folder.

---
 libc/src/__support/FPUtil/FEnvImpl.h          |  8 +--
 libc/src/__support/FPUtil/FPBits.h            | 25 ++++----
 libc/src/__support/FPUtil/NormalFloat.h       |  5 +-
 libc/src/__support/FPUtil/bfloat16.h          |  2 +-
 libc/src/__support/FPUtil/dyadic_float.h      | 14 ++---
 .../src/__support/FPUtil/except_value_utils.h | 61 +++++++++++++------
 libc/src/__support/FPUtil/generic/FMA.h       |  2 +-
 libc/src/__support/FPUtil/generic/sqrt.h      | 14 +++--
 .../FPUtil/generic/sqrt_80_bit_long_double.h  | 10 +--
 libc/src/__support/FPUtil/rounding_mode.h     | 10 +--
 .../FPUtil/x86_64/NextAfterLongDouble.h       |  3 +-
 .../FPUtil/x86_64/NextUpDownLongDouble.h      |  2 +-
 12 files changed, 91 insertions(+), 65 deletions(-)

diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h
index a21f511bd72b8..89188d20297e6 100644
--- a/libc/src/__support/FPUtil/FEnvImpl.h
+++ b/libc/src/__support/FPUtil/FEnvImpl.h
@@ -123,7 +123,7 @@ LIBC_INLINE int set_env(const fenv_t *) { return 0; }
 namespace LIBC_NAMESPACE_DECL {
 namespace fputil {
 
-LIBC_INLINE static constexpr int
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
 clear_except_if_required([[maybe_unused]] int excepts) {
   if (cpp::is_constant_evaluated()) {
     return 0;
@@ -136,7 +136,7 @@ clear_except_if_required([[maybe_unused]] int excepts) {
   }
 }
 
-LIBC_INLINE static constexpr int
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
 set_except_if_required([[maybe_unused]] int excepts) {
   if (cpp::is_constant_evaluated()) {
     return 0;
@@ -149,7 +149,7 @@ set_except_if_required([[maybe_unused]] int excepts) {
   }
 }
 
-LIBC_INLINE static constexpr int
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
 raise_except_if_required([[maybe_unused]] int excepts) {
   if (cpp::is_constant_evaluated()) {
     return 0;
@@ -162,7 +162,7 @@ raise_except_if_required([[maybe_unused]] int excepts) {
   }
 }
 
-LIBC_INLINE static constexpr void
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
 set_errno_if_required([[maybe_unused]] int err) {
   if (!cpp::is_constant_evaluated()) {
 #ifndef LIBC_MATH_HAS_NO_ERRNO
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 7028fd4f38950..c52699e17e225 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -835,21 +835,22 @@ struct FPBits final : public internal::FPRepImpl<get_fp_type<T>(), FPBits<T>> {
   // Constructors.
   LIBC_INLINE constexpr FPBits() = default;
 
-  template <typename XType> LIBC_INLINE constexpr explicit FPBits(XType x) {
-    using Unqual = typename cpp::remove_cv_t<XType>;
-    if constexpr (cpp::is_same_v<Unqual, T>) {
-      UP::bits = cpp::bit_cast<StorageType>(x);
-    } else if constexpr (cpp::is_same_v<Unqual, StorageType>) {
-      UP::bits = x;
-    } else {
-      // We don't want accidental type promotions/conversions, so we require
-      // exact type match.
-      static_assert(cpp::always_false<XType>);
-    }
+  template <
+      typename XType,
+      cpp::enable_if_t<cpp::is_same_v<cpp::remove_cv_t<XType>, T>, int> = 0>
+  LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR explicit FPBits(XType x) {
+    UP::bits = cpp::bit_cast<StorageType>(x);
   }
 
+  template <typename XType,
+            cpp::enable_if_t<
+                cpp::is_same_v<cpp::remove_cv_t<XType>, StorageType>, int> = 0>
+  LIBC_INLINE constexpr explicit FPBits(XType x) : UP(x) {}
+
   // Floating-point conversions.
-  LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(UP::bits); }
+  LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR T get_val() const {
+    return cpp::bit_cast<T>(UP::bits);
+  }
 };
 
 } // namespace fputil
diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h
index 5123a3e217f72..2da317a356405 100644
--- a/libc/src/__support/FPUtil/NormalFloat.h
+++ b/libc/src/__support/FPUtil/NormalFloat.h
@@ -95,7 +95,7 @@ template <typename T> struct NormalFloat {
     return result;
   }
 
-  LIBC_INLINE constexpr operator T() const {
+  LIBC_INLINE operator T() const {
     int biased_exponent = exponent + FPBits<T>::EXP_BIAS;
     // Max exponent is of the form 0xFF...E. That is why -2 and not -1.
     constexpr int MAX_EXPONENT_VALUE = (1 << FPBits<T>::EXP_LEN) - 2;
@@ -216,8 +216,7 @@ NormalFloat<long double>::init_from_bits(FPBits<long double> bits) {
   }
 }
 
-template <>
-LIBC_INLINE constexpr NormalFloat<long double>::operator long double() const {
+template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {
   using LDBits = FPBits<long double>;
   int biased_exponent = exponent + LDBits::EXP_BIAS;
   // Max exponent is of the form 0xFF...E. That is why -2 and not -1.
diff --git a/libc/src/__support/FPUtil/bfloat16.h b/libc/src/__support/FPUtil/bfloat16.h
index 5c8f3b7e6c77a..638500d94cef2 100644
--- a/libc/src/__support/FPUtil/bfloat16.h
+++ b/libc/src/__support/FPUtil/bfloat16.h
@@ -92,7 +92,7 @@ struct BFloat16 {
     return fputil::greater_than_or_equals(*this, other);
   }
 
-  LIBC_INLINE constexpr BFloat16 operator-() const {
+  LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR BFloat16 operator-() const {
     fputil::FPBits<bfloat16> result(*this);
     result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS);
     return result.get_val();
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 8ce041247716b..7e4ea2f1a81be 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -39,7 +39,7 @@ namespace fputil {
 // Return value is +1 if the value should be rounded up; -1 if it should be
 // rounded down; 0 if it's exact and needs no rounding.
 template <size_t Bits>
-LIBC_INLINE constexpr int
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
 rounding_direction(const LIBC_NAMESPACE::UInt<Bits> &value, size_t rshift,
                    Sign logical_sign) {
   if (rshift == 0 || (rshift < Bits && (value << (Bits - rshift)) == 0) ||
@@ -95,7 +95,7 @@ template <size_t Bits> struct DyadicFloat {
   LIBC_INLINE constexpr DyadicFloat() = default;
 
   template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-  LIBC_INLINE constexpr DyadicFloat(T x) {
+  LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR DyadicFloat(T x) {
     static_assert(FPBits<T>::FRACTION_LEN < Bits);
     FPBits<T> x_bits(x);
     sign = x_bits.sign();
@@ -152,7 +152,7 @@ template <size_t Bits> struct DyadicFloat {
   // Produce a correctly rounded DyadicFloat from a too-large mantissa,
   // by shifting it down and rounding if necessary.
   template <size_t MantissaBits>
-  LIBC_INLINE constexpr static DyadicFloat<Bits>
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT static DyadicFloat<Bits>
   round(Sign result_sign, int result_exponent,
         const LIBC_NAMESPACE::UInt<MantissaBits> &input_mantissa,
         size_t rshift) {
@@ -171,7 +171,7 @@ template <size_t Bits> struct DyadicFloat {
   }
 
   template <typename T, bool ShouldSignalExceptions>
-  LIBC_INLINE constexpr cpp::enable_if_t<
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT cpp::enable_if_t<
       cpp::is_floating_point_v<T> && (FPBits<T>::FRACTION_LEN < Bits), T>
   generic_as() const {
     using FPBits = FPBits<T>;
@@ -284,7 +284,7 @@ template <size_t Bits> struct DyadicFloat {
             typename = cpp::enable_if_t<cpp::is_floating_point_v<T> &&
                                             (FPBits<T>::FRACTION_LEN < Bits),
                                         void>>
-  LIBC_INLINE constexpr T fast_as() const {
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT T fast_as() const {
     if (LIBC_UNLIKELY(mantissa.is_zero()))
       return FPBits<T>::zero(sign).get_val();
 
@@ -411,7 +411,7 @@ template <size_t Bits> struct DyadicFloat {
             typename = cpp::enable_if_t<cpp::is_floating_point_v<T> &&
                                             (FPBits<T>::FRACTION_LEN < Bits),
                                         void>>
-  LIBC_INLINE constexpr T as() const {
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT T as() const {
     if constexpr (cpp::is_same_v<T, bfloat16>
 #if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
                   || cpp::is_same_v<T, float16>
@@ -453,7 +453,7 @@ template <size_t Bits> struct DyadicFloat {
     return new_mant;
   }
 
-  LIBC_INLINE constexpr MantissaType
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT MantissaType
   as_mantissa_type_rounded(int *round_dir_out = nullptr) const {
     int round_dir = 0;
     MantissaType new_mant;
diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h
index 5f767769974d2..37ecc52784c16 100644
--- a/libc/src/__support/FPUtil/except_value_utils.h
+++ b/libc/src/__support/FPUtil/except_value_utils.h
@@ -53,7 +53,8 @@ template <typename T, size_t N> struct ExceptValues {
 
   Mapping values[N];
 
-  LIBC_INLINE constexpr cpp::optional<T> lookup(StorageType x_bits) const {
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT cpp::optional<T>
+  lookup(StorageType x_bits) const {
     for (size_t i = 0; i < N; ++i) {
       if (LIBC_UNLIKELY(x_bits == values[i].input)) {
         StorageType out_bits = values[i].rnd_towardzero_result;
@@ -74,8 +75,8 @@ template <typename T, size_t N> struct ExceptValues {
     return cpp::nullopt;
   }
 
-  LIBC_INLINE constexpr cpp::optional<T> lookup_odd(StorageType x_abs,
-                                                    bool sign) const {
+  LIBC_INLINE LIBC_CONSTEXPR_DEFAULT cpp::optional<T>
+  lookup_odd(StorageType x_abs, bool sign) const {
     for (size_t i = 0; i < N; ++i) {
       if (LIBC_UNLIKELY(x_abs == values[i].input)) {
         StorageType out_bits = values[i].rnd_towardzero_result;
@@ -111,30 +112,52 @@ template <typename T, size_t N> struct ExceptValues {
 };
 
 // Helper functions to set results for exceptional cases.
-template <typename T> LIBC_INLINE T round_result_slightly_down(T value_rn) {
-  volatile T tmp = value_rn;
-  tmp -= FPBits<T>::min_normal().get_val();
-  return tmp;
+template <typename T>
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT T round_result_slightly_down(T value_rn) {
+  if (cpp::is_constant_evaluated()) {
+    return value_rn;
+  } else {
+    volatile T tmp = value_rn;
+    tmp -= FPBits<T>::min_normal().get_val();
+    return tmp;
+  }
 }
 
-template <typename T> LIBC_INLINE T round_result_slightly_up(T value_rn) {
-  volatile T tmp = value_rn;
-  tmp += FPBits<T>::min_normal().get_val();
-  return tmp;
+template <typename T>
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT T round_result_slightly_up(T value_rn) {
+  if (cpp::is_constant_evaluated()) {
+    return value_rn;
+  } else {
+    volatile T tmp = value_rn;
+    tmp += FPBits<T>::min_normal().get_val();
+    return tmp;
+  }
 }
 
 #if defined(LIBC_TYPES_HAS_FLOAT16) &&                                         \
     !defined(LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS)
-template <> LIBC_INLINE float16 round_result_slightly_down(float16 value_rn) {
-  volatile float tmp = value_rn;
-  tmp -= FPBits<float16>::min_normal().get_val();
-  return cast<float16>(tmp);
+template <>
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT float16
+round_result_slightly_down(float16 value_rn) {
+  if (cpp::is_constant_evaluated()) {
+    return value_rn;
+  } else {
+    volatile float tmp = value_rn;
+    tmp -= FPBits<float16>::min_normal().get_val();
+    return cast<float16>(tmp);
+  }
 }
 
-template <> LIBC_INLINE float16 round_result_slightly_up(float16 value_rn) {
-  volatile float tmp = value_rn;
-  tmp += FPBits<float16>::min_normal().get_val();
-  return cast<float16>(tmp);
+template <>
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT float16
+round_result_slightly_up(float16 value_rn) {
+  if (cpp::is_constant_evaluated()) {
+    return value_rn;
+  } else {
+    volatile float tmp = value_rn;
+    tmp += FPBits<float16>::min_normal().get_val();
+    return cast<float16>(tmp);
+  }
 }
 #endif
 
diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h
index 7b46978d0c8af..0de4f98969b72 100644
--- a/libc/src/__support/FPUtil/generic/FMA.h
+++ b/libc/src/__support/FPUtil/generic/FMA.h
@@ -168,7 +168,7 @@ fma(InType x, InType y, InType z) {
   constexpr InStorageType IMPLICIT_MASK =
       InFPBits::SIG_MASK - InFPBits::FRACTION_MASK;
 
-  constexpr InType DENORMAL_SCALING =
+  LIBC_BIT_CAST_CONSTEXPR_VAR InType DENORMAL_SCALING =
       InFPBits::create_value(
           Sign::POS, InFPBits::FRACTION_LEN + InFPBits::EXP_BIAS, IMPLICIT_MASK)
           .get_val();
diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h
index 4e452a87050b1..69087bd93f083 100644
--- a/libc/src/__support/FPUtil/generic/sqrt.h
+++ b/libc/src/__support/FPUtil/generic/sqrt.h
@@ -41,8 +41,8 @@ template <> struct SpecialLongDouble<long double> {
 #endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
 
 template <typename T>
-LIBC_INLINE void normalize(int &exponent,
-                           typename FPBits<T>::StorageType &mantissa) {
+LIBC_INLINE constexpr void
+normalize(int &exponent, typename FPBits<T>::StorageType &mantissa) {
   const int shift =
       cpp::countl_zero(mantissa) -
       (8 * static_cast<int>(sizeof(mantissa)) - 1 - FPBits<T>::FRACTION_LEN);
@@ -52,12 +52,14 @@ LIBC_INLINE void normalize(int &exponent,
 
 #ifdef LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
 template <>
-LIBC_INLINE void normalize<long double>(int &exponent, uint64_t &mantissa) {
+LIBC_INLINE constexpr void normalize<long double>(int &exponent,
+                                                  uint64_t &mantissa) {
   normalize<double>(exponent, mantissa);
 }
 #elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
 template <>
-LIBC_INLINE void normalize<long double>(int &exponent, UInt128 &mantissa) {
+LIBC_INLINE constexpr void normalize<long double>(int &exponent,
+                                                  UInt128 &mantissa) {
   const uint64_t hi_bits = static_cast<uint64_t>(mantissa >> 64);
   const int shift =
       hi_bits ? (cpp::countl_zero(hi_bits) - 15)
@@ -72,7 +74,7 @@ LIBC_INLINE void normalize<long double>(int &exponent, UInt128 &mantissa) {
 // Correctly rounded IEEE 754 SQRT for all rounding modes.
 // Shift-and-add algorithm.
 template <typename OutType, typename InType>
-LIBC_INLINE static constexpr cpp::enable_if_t<
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT static cpp::enable_if_t<
     cpp::is_floating_point_v<OutType> && cpp::is_floating_point_v<InType> &&
         sizeof(OutType) <= sizeof(InType),
     OutType>
@@ -92,7 +94,7 @@ sqrt(InType x) {
         DyadicFloat<cpp::bit_ceil(static_cast<size_t>(InFPBits::STORAGE_LEN))>;
 
     constexpr InStorageType ONE = InStorageType(1) << InFPBits::FRACTION_LEN;
-    constexpr auto FLT_NAN = OutFPBits::quiet_nan().get_val();
+    LIBC_BIT_CAST_CONSTEXPR_VAR auto FLT_NAN = OutFPBits::quiet_nan().get_val();
 
     InFPBits bits(x);
 
diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
index 0ba836d17a085..cc692d0fc4c26 100644
--- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
+++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
@@ -21,8 +21,8 @@ namespace LIBC_NAMESPACE_DECL {
 namespace fputil {
 namespace x86 {
 
-LIBC_INLINE void normalize(int &exponent,
-                           FPBits<long double>::StorageType &mantissa) {
+LIBC_INLINE constexpr void
+normalize(int &exponent, FPBits<long double>::StorageType &mantissa) {
   const unsigned int shift = static_cast<unsigned int>(
       static_cast<size_t>(cpp::countl_zero(static_cast<uint64_t>(mantissa))) -
       (8 * sizeof(uint64_t) - 1 - FPBits<long double>::FRACTION_LEN));
@@ -32,16 +32,16 @@ LIBC_INLINE void normalize(int &exponent,
 
 // if constexpr statement in sqrt.h still requires x86::sqrt to be declared
 // even when it's not used.
-LIBC_INLINE long double sqrt(long double x);
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT long double sqrt(long double x);
 
 // Correctly rounded SQRT for all rounding modes.
 // Shift-and-add algorithm.
 #if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
-LIBC_INLINE long double sqrt(long double x) {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT long double sqrt(long double x) {
   using LDBits = FPBits<long double>;
   using StorageType = typename LDBits::StorageType;
   constexpr StorageType ONE = StorageType(1) << int(LDBits::FRACTION_LEN);
-  constexpr auto LDNAN = LDBits::quiet_nan().get_val();
+  LIBC_BIT_CAST_CONSTEXPR_VAR auto LDNAN = LDBits::quiet_nan().get_val();
 
   LDBits bits(x);
 
diff --git a/libc/src/__support/FPUtil/rounding_mode.h b/libc/src/__support/FPUtil/rounding_mode.h
index 92061ea13e203..6ce693d41da50 100644
--- a/libc/src/__support/FPUtil/rounding_mode.h
+++ b/libc/src/__support/FPUtil/rounding_mode.h
@@ -80,7 +80,7 @@ LIBC_INLINE int quick_get_round() {
 
 } // namespace generic
 
-LIBC_INLINE constexpr bool fenv_is_round_up() {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_up() {
   if (cpp::is_constant_evaluated()) {
     return false;
   } else {
@@ -88,7 +88,7 @@ LIBC_INLINE constexpr bool fenv_is_round_up() {
   }
 }
 
-LIBC_INLINE constexpr bool fenv_is_round_down() {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_down() {
   if (cpp::is_constant_evaluated()) {
     return false;
   } else {
@@ -96,7 +96,7 @@ LIBC_INLINE constexpr bool fenv_is_round_down() {
   }
 }
 
-LIBC_INLINE constexpr bool fenv_is_round_to_nearest() {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_to_nearest() {
   if (cpp::is_constant_evaluated()) {
     return true;
   } else {
@@ -104,7 +104,7 @@ LIBC_INLINE constexpr bool fenv_is_round_to_nearest() {
   }
 }
 
-LIBC_INLINE constexpr bool fenv_is_round_to_zero() {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_to_zero() {
   if (cpp::is_constant_evaluated()) {
     return false;
   } else {
@@ -113,7 +113,7 @@ LIBC_INLINE constexpr bool fenv_is_round_to_zero() {
 }
 
 // Quick free standing get rounding mode based on the above observations.
-LIBC_INLINE constexpr int quick_get_round() {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int quick_get_round() {
   if (cpp::is_constant_evaluated()) {
     return FE_TONEAREST;
   } else {
diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
index aa9f4a5e39c2d..2ea36666c9a46 100644
--- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
+++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
@@ -24,7 +24,8 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace fputil {
 
-LIBC_INLINE constexpr long double nextafter(long double from, long double to) {
+LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR long double nextafter(long double from,
+                                                          long double to) {
   using FPBits = FPBits<long double>;
   FPBits from_bits(from);
   if (from_bits.is_nan())
diff --git a/libc/src/__support/FPUtil/x86_64/NextUpDownLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextUpDownLongDouble.h
index 31869975ac5ad..589328ae2a425 100644
--- a/libc/src/__support/FPUtil/x86_64/NextUpDownLongDouble.h
+++ b/libc/src/__support/FPUtil/x86_64/NextUpDownLongDouble.h
@@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL {
 namespace fputil {
 
 template <bool IsDown>
-LIBC_INLINE constexpr long double nextupdown(long double x) {
+LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR long double nextupdown(long double x) {
   constexpr Sign sign = IsDown ? Sign::NEG : Sign::POS;
 
   using FPBits_t = FPBits<long double>;

>From 660d9767fa29a132a6e2cd9c2158b096045199b3 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 04:56:41 +0000
Subject: [PATCH 4/7] Apply fine-grained constexpr annotations to src/__support
 folder.

---
 libc/src/__support/big_int.h           | 26 ++++++++++++++------------
 libc/src/__support/complex_basic_ops.h |  4 ++--
 2 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/libc/src/__support/big_int.h b/libc/src/__support/big_int.h
index a6dcff27ca167..0e5c038ec356e 100644
--- a/libc/src/__support/big_int.h
+++ b/libc/src/__support/big_int.h
@@ -242,10 +242,9 @@ LIBC_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst,
 
 template <typename word, size_t N>
 LIBC_INLINE constexpr bool is_negative(const cpp::array<word, N> &array) {
-  using signed_word = cpp::make_signed_t<word>;
-  return cpp::bit_cast<signed_word>(array.back()) < 0;
+  constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
+  return (array.back() >> (WORD_BITS - 1)) != 0;
 }
-
 // An enum for the shift function below.
 enum Direction { LEFT, RIGHT };
 
@@ -257,6 +256,7 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
                                                 size_t offset) {
   static_assert(direction == LEFT || direction == RIGHT);
   constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
+#if LIBC_HAS_BUILTIN_BIT_CAST
 #ifdef LIBC_TYPES_HAS_INT128
   constexpr size_t TOTAL_BITS = N * WORD_BITS;
   if constexpr (TOTAL_BITS == 128 &&
@@ -270,6 +270,8 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
     return cpp::bit_cast<cpp::array<word, N>>(tmp);
   }
 #endif
+#endif // LIBC_HAS_BUILTIN_BIT_CAST
+
   if (LIBC_UNLIKELY(offset == 0))
     return array;
   const bool is_neg = is_signed && is_negative(array);
@@ -366,7 +368,7 @@ struct BigInt {
   LIBC_INLINE constexpr BigInt(
       const BigInt<OtherBits, OtherSigned, OtherWordType> &other) {
     using BigIntOther = BigInt<OtherBits, OtherSigned, OtherWordType>;
-    const bool should_sign_extend = Signed && other.is_neg();
+    [[maybe_unused]] const bool should_sign_extend = Signed && other.is_neg();
 
     static_assert(!(Bits == OtherBits && WORD_SIZE != BigIntOther::WORD_SIZE) &&
                   "This is currently untested for casting between bigints with "
@@ -1184,7 +1186,7 @@ namespace cpp {
 
 // Specialization of cpp::bit_cast ('bit.h') from T to BigInt.
 template <typename To, typename From>
-LIBC_INLINE constexpr cpp::enable_if_t<
+LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR cpp::enable_if_t<
     (sizeof(To) == sizeof(From)) && cpp::is_trivially_copyable<To>::value &&
         cpp::is_trivially_copyable<From>::value && is_big_int<To>::value,
     To>
@@ -1197,13 +1199,13 @@ bit_cast(const From &from) {
 
 // Specialization of cpp::bit_cast ('bit.h') from BigInt to T.
 template <typename To, size_t Bits>
-LIBC_INLINE constexpr cpp::enable_if_t<
-    sizeof(To) == sizeof(UInt<Bits>) &&
-        cpp::is_trivially_constructible<To>::value &&
-        cpp::is_trivially_copyable<To>::value &&
-        cpp::is_trivially_copyable<UInt<Bits>>::value,
-    To>
-bit_cast(const UInt<Bits> &from) {
+LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR
+    cpp::enable_if_t<sizeof(To) == sizeof(UInt<Bits>) &&
+                         cpp::is_trivially_constructible<To>::value &&
+                         cpp::is_trivially_copyable<To>::value &&
+                         cpp::is_trivially_copyable<UInt<Bits>>::value,
+                     To>
+    bit_cast(const UInt<Bits> &from) {
   return cpp::bit_cast<To>(from.val);
 }
 
diff --git a/libc/src/__support/complex_basic_ops.h b/libc/src/__support/complex_basic_ops.h
index 5992ebec0786c..bf488730d1c72 100644
--- a/libc/src/__support/complex_basic_ops.h
+++ b/libc/src/__support/complex_basic_ops.h
@@ -15,13 +15,13 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-template <typename T> LIBC_INLINE constexpr T conjugate(T c) {
+template <typename T> LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR T conjugate(T c) {
   Complex<make_real_t<T>> c_c = cpp::bit_cast<Complex<make_real_t<T>>>(c);
   c_c.imag = -c_c.imag;
   return cpp::bit_cast<T>(c_c);
 }
 
-template <typename T> LIBC_INLINE constexpr T project(T c) {
+template <typename T> LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR T project(T c) {
   using real_t = make_real_t<T>;
   Complex<real_t> c_c = cpp::bit_cast<Complex<real_t>>(c);
   if (fputil::FPBits<real_t>(c_c.real).is_inf() ||

>From 51bd08ae08d43dc8c74875258524157a3e3432ad Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 04:57:40 +0000
Subject: [PATCH 5/7] Remove or update constexpr annotations for functions in
 src/__support/math folder.

---
 libc/src/__support/math/acos.h       |  2 +-
 libc/src/__support/math/acosf.h      |  2 +-
 libc/src/__support/math/acoshf.h     |  2 +-
 libc/src/__support/math/asinf.h      |  2 +-
 libc/src/__support/math/asinhf.h     |  2 +-
 libc/src/__support/math/atan.h       |  2 +-
 libc/src/__support/math/atan2.h      |  2 +-
 libc/src/__support/math/atan2f.h     |  2 +-
 libc/src/__support/math/atan2f128.h  |  2 +-
 libc/src/__support/math/atanf.h      |  2 +-
 libc/src/__support/math/atanhf.h     |  2 +-
 libc/src/__support/math/cbrt.h       |  2 +-
 libc/src/__support/math/cbrtf.h      |  2 +-
 libc/src/__support/math/cos.h        |  2 +-
 libc/src/__support/math/cosf.h       |  4 ++--
 libc/src/__support/math/coshf.h      |  2 +-
 libc/src/__support/math/cospif.h     |  2 +-
 libc/src/__support/math/dsqrtf128.h  |  2 +-
 libc/src/__support/math/dsqrtl.h     |  2 +-
 libc/src/__support/math/erff.h       |  2 +-
 libc/src/__support/math/exp10.h      |  9 ++++-----
 libc/src/__support/math/exp10f.h     |  2 +-
 libc/src/__support/math/exp10m1f.h   |  2 +-
 libc/src/__support/math/exp2.h       | 10 +++++-----
 libc/src/__support/math/exp2f.h      |  2 +-
 libc/src/__support/math/exp2m1f.h    |  2 +-
 libc/src/__support/math/expf.h       |  2 +-
 libc/src/__support/math/expm1.h      |  9 ++++-----
 libc/src/__support/math/expm1f.h     |  2 +-
 libc/src/__support/math/fsqrt.h      |  4 +++-
 libc/src/__support/math/fsqrtf128.h  |  2 +-
 libc/src/__support/math/fsqrtl.h     |  2 +-
 libc/src/__support/math/log.h        |  2 +-
 libc/src/__support/math/nextafterl.h |  2 +-
 libc/src/__support/math/nextdownl.h  |  2 +-
 libc/src/__support/math/nextupl.h    |  2 +-
 libc/src/__support/math/pow.h        |  4 ++--
 libc/src/__support/math/powf.h       |  6 +++---
 libc/src/__support/math/rsqrtf.h     |  2 +-
 libc/src/__support/math/sin.h        |  2 +-
 libc/src/__support/math/sinhf.h      |  2 +-
 libc/src/__support/math/tan.h        |  2 +-
 42 files changed, 58 insertions(+), 58 deletions(-)

diff --git a/libc/src/__support/math/acos.h b/libc/src/__support/math/acos.h
index 6b419449176fd..2ee7974358b18 100644
--- a/libc/src/__support/math/acos.h
+++ b/libc/src/__support/math/acos.h
@@ -24,7 +24,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr double acos(double x) {
+LIBC_INLINE double acos(double x) {
   using DoubleDouble = fputil::DoubleDouble;
   using namespace asin_internal;
   using FPBits = fputil::FPBits<double>;
diff --git a/libc/src/__support/math/acosf.h b/libc/src/__support/math/acosf.h
index ae93abe7e716a..abfc8ce14c8b0 100644
--- a/libc/src/__support/math/acosf.h
+++ b/libc/src/__support/math/acosf.h
@@ -46,7 +46,7 @@ LIBC_INLINE_VAR constexpr fputil::ExceptValues<float, N_EXCEPTS> ACOSF_EXCEPTS =
 
 } // namespace acosf_internal
 
-LIBC_INLINE constexpr float acosf(float x) {
+LIBC_INLINE float acosf(float x) {
   using namespace acosf_internal;
   using namespace inv_trigf_utils_internal;
   using FPBits = typename fputil::FPBits<float>;
diff --git a/libc/src/__support/math/acoshf.h b/libc/src/__support/math/acoshf.h
index b111a21c07b70..02b2a3d5a513d 100644
--- a/libc/src/__support/math/acoshf.h
+++ b/libc/src/__support/math/acoshf.h
@@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float acoshf(float x) {
+LIBC_INLINE float acoshf(float x) {
   using namespace acoshf_internal;
   using FPBits_t = typename fputil::FPBits<float>;
   FPBits_t xbits(x);
diff --git a/libc/src/__support/math/asinf.h b/libc/src/__support/math/asinf.h
index 08cfb192754e4..8bafce5d8ba3d 100644
--- a/libc/src/__support/math/asinf.h
+++ b/libc/src/__support/math/asinf.h
@@ -23,7 +23,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float asinf(float x) {
+LIBC_INLINE float asinf(float x) {
   using namespace inv_trigf_utils_internal;
   using FPBits = typename fputil::FPBits<float>;
 
diff --git a/libc/src/__support/math/asinhf.h b/libc/src/__support/math/asinhf.h
index e420eae221c3e..ac77eb2085853 100644
--- a/libc/src/__support/math/asinhf.h
+++ b/libc/src/__support/math/asinhf.h
@@ -21,7 +21,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float asinhf(float x) {
+LIBC_INLINE float asinhf(float x) {
   using namespace acoshf_internal;
   using FPBits_t = typename fputil::FPBits<float>;
   FPBits_t xbits(x);
diff --git a/libc/src/__support/math/atan.h b/libc/src/__support/math/atan.h
index db60311bd746d..8a11167a6268e 100644
--- a/libc/src/__support/math/atan.h
+++ b/libc/src/__support/math/atan.h
@@ -52,7 +52,7 @@ namespace math {
 //      So we can return:
 //        atan(x) = sign(x) * (pi/2 - epsilon)
 
-LIBC_INLINE constexpr double atan(double x) {
+LIBC_INLINE double atan(double x) {
 
   using namespace atan_internal;
   using FPBits = fputil::FPBits<double>;
diff --git a/libc/src/__support/math/atan2.h b/libc/src/__support/math/atan2.h
index f59d92b6dc19c..a009af39354a1 100644
--- a/libc/src/__support/math/atan2.h
+++ b/libc/src/__support/math/atan2.h
@@ -75,7 +75,7 @@ namespace math {
 // and relative errors bounded by:
 //   |(atan(u) - P(u)) / P(u)| < u^10 / 11 < 2^-73.
 
-LIBC_INLINE constexpr double atan2(double y, double x) {
+LIBC_INLINE double atan2(double y, double x) {
   using namespace atan_internal;
   using FPBits = fputil::FPBits<double>;
 
diff --git a/libc/src/__support/math/atan2f.h b/libc/src/__support/math/atan2f.h
index 15d1fce2b707c..3a56291a832d3 100644
--- a/libc/src/__support/math/atan2f.h
+++ b/libc/src/__support/math/atan2f.h
@@ -239,7 +239,7 @@ LIBC_INLINE float atan2f_double_double(double num_d, double den_d, double q_d,
 // 0x1.aec6f...p-100
 // which is about rounding errors of double-double (2^-104).
 
-LIBC_INLINE constexpr float atan2f(float y, float x) {
+LIBC_INLINE float atan2f(float y, float x) {
   using namespace atan2f_internal;
   using namespace inv_trigf_utils_internal;
   using FPBits = typename fputil::FPBits<float>;
diff --git a/libc/src/__support/math/atan2f128.h b/libc/src/__support/math/atan2f128.h
index d04cf6f49d4ea..e72499ec5af20 100644
--- a/libc/src/__support/math/atan2f128.h
+++ b/libc/src/__support/math/atan2f128.h
@@ -81,7 +81,7 @@ namespace math {
 // and relative errors bounded by:
 //   |(atan(u) - P(u)) / P(u)| < 2^-114.
 
-LIBC_INLINE constexpr float128 atan2f128(float128 y, float128 x) {
+LIBC_INLINE float128 atan2f128(float128 y, float128 x) {
   using Float128 = fputil::DyadicFloat<128>;
 
   constexpr Float128 ZERO = {Sign::POS, 0, 0_u128};
diff --git a/libc/src/__support/math/atanf.h b/libc/src/__support/math/atanf.h
index d583572ea4727..78b8b25b8b2c6 100644
--- a/libc/src/__support/math/atanf.h
+++ b/libc/src/__support/math/atanf.h
@@ -30,7 +30,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float atanf(float x) {
+LIBC_INLINE float atanf(float x) {
   using namespace inv_trigf_utils_internal;
   using FPBits = typename fputil::FPBits<float>;
 
diff --git a/libc/src/__support/math/atanhf.h b/libc/src/__support/math/atanhf.h
index 16d46994e2705..684b74a46d353 100644
--- a/libc/src/__support/math/atanhf.h
+++ b/libc/src/__support/math/atanhf.h
@@ -19,7 +19,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float atanhf(float x) {
+LIBC_INLINE float atanhf(float x) {
   using namespace acoshf_internal;
   using FPBits = typename fputil::FPBits<float>;
 
diff --git a/libc/src/__support/math/cbrt.h b/libc/src/__support/math/cbrt.h
index a781ed36238b8..1998731aeb4f8 100644
--- a/libc/src/__support/math/cbrt.h
+++ b/libc/src/__support/math/cbrt.h
@@ -144,7 +144,7 @@ LIBC_INLINE constexpr double get_error(const DoubleDouble &x_3,
 // exceptional handling, similar to what was done in the CORE-MATH project:
 // https://gitlab.inria.fr/core-math/core-math/-/blob/master/src/binary64/cbrt/cbrt.c
 
-LIBC_INLINE constexpr double cbrt(double x) {
+LIBC_INLINE double cbrt(double x) {
   using DoubleDouble = fputil::DoubleDouble;
   using namespace cbrt_internal;
   using FPBits = fputil::FPBits<double>;
diff --git a/libc/src/__support/math/cbrtf.h b/libc/src/__support/math/cbrtf.h
index 35e60562a39c0..5f0c413088a36 100644
--- a/libc/src/__support/math/cbrtf.h
+++ b/libc/src/__support/math/cbrtf.h
@@ -19,7 +19,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float cbrtf(float x) {
+LIBC_INLINE float cbrtf(float x) {
   // Look up table for 2^(i/3) for i = 0, 1, 2.
   constexpr double CBRT2[3] = {1.0, 0x1.428a2f98d728bp0, 0x1.965fea53d6e3dp0};
 
diff --git a/libc/src/__support/math/cos.h b/libc/src/__support/math/cos.h
index e6a37c132cd80..93ca20ed41e03 100644
--- a/libc/src/__support/math/cos.h
+++ b/libc/src/__support/math/cos.h
@@ -30,7 +30,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr double cos(double x) {
+LIBC_INLINE double cos(double x) {
   using namespace range_reduction_double_internal;
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
diff --git a/libc/src/__support/math/cosf.h b/libc/src/__support/math/cosf.h
index f6ead968ac26e..affff7117562a 100644
--- a/libc/src/__support/math/cosf.h
+++ b/libc/src/__support/math/cosf.h
@@ -26,7 +26,7 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace math {
 
-LIBC_INLINE constexpr float cosf(float x) {
+LIBC_INLINE float cosf(float x) {
   return sincosf_float_eval::sincosf_eval</*IS_SIN*/ false>(x);
 }
 
@@ -41,7 +41,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float cosf(float x) {
+LIBC_INLINE float cosf(float x) {
   using namespace sincosf_utils_internal;
 
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
diff --git a/libc/src/__support/math/coshf.h b/libc/src/__support/math/coshf.h
index aa0988f9711f1..d80d86af301ab 100644
--- a/libc/src/__support/math/coshf.h
+++ b/libc/src/__support/math/coshf.h
@@ -20,7 +20,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float coshf(float x) {
+LIBC_INLINE float coshf(float x) {
   using namespace sinhfcoshf_internal;
   using FPBits = typename fputil::FPBits<float>;
 
diff --git a/libc/src/__support/math/cospif.h b/libc/src/__support/math/cospif.h
index 3d0a335408722..49100feba3230 100644
--- a/libc/src/__support/math/cospif.h
+++ b/libc/src/__support/math/cospif.h
@@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float cospif(float x) {
+LIBC_INLINE float cospif(float x) {
   using namespace sincosf_utils_internal;
   using FPBits = typename fputil::FPBits<float>;
 
diff --git a/libc/src/__support/math/dsqrtf128.h b/libc/src/__support/math/dsqrtf128.h
index 241e1b437982a..6b0521410dc43 100644
--- a/libc/src/__support/math/dsqrtf128.h
+++ b/libc/src/__support/math/dsqrtf128.h
@@ -19,7 +19,7 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace math {
 
-LIBC_INLINE constexpr double dsqrtf128(float128 x) {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT double dsqrtf128(float128 x) {
   return fputil::sqrt<double>(x);
 }
 
diff --git a/libc/src/__support/math/dsqrtl.h b/libc/src/__support/math/dsqrtl.h
index 14decf8c6ed77..110f8aff92f56 100644
--- a/libc/src/__support/math/dsqrtl.h
+++ b/libc/src/__support/math/dsqrtl.h
@@ -15,7 +15,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr double dsqrtl(long double x) {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT double dsqrtl(long double x) {
   return fputil::sqrt<double>(x);
 }
 
diff --git a/libc/src/__support/math/erff.h b/libc/src/__support/math/erff.h
index a40b927c60a26..63919734cf744 100644
--- a/libc/src/__support/math/erff.h
+++ b/libc/src/__support/math/erff.h
@@ -19,7 +19,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float erff(float x) {
+LIBC_INLINE float erff(float x) {
 
   // Polynomials approximating erf(x)/x on ( k/8, (k + 1)/8 ) generated by
   // Sollya with: > P = fpminimax(erf(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|],
diff --git a/libc/src/__support/math/exp10.h b/libc/src/__support/math/exp10.h
index c2ca627d20db9..17dc70f7a2fd2 100644
--- a/libc/src/__support/math/exp10.h
+++ b/libc/src/__support/math/exp10.h
@@ -83,8 +83,7 @@ LIBC_INLINE double exp10_poly_approx_d(double dx) {
 // > P = fpminimax((10^x - 1)/x, 5, [|DD...|], [-2^-14, 2^-14]);
 // Error bounds:
 //   | output - 10^(dx) | < 2^-101
-LIBC_INLINE constexpr DoubleDouble
-exp10_poly_approx_dd(const DoubleDouble &dx) {
+LIBC_INLINE DoubleDouble exp10_poly_approx_dd(const DoubleDouble &dx) {
   // Taylor polynomial.
   constexpr DoubleDouble COEFFS[] = {
       {0, 0x1p0},
@@ -106,7 +105,7 @@ exp10_poly_approx_dd(const DoubleDouble &dx) {
 // Return exp(dx) ~ 1 + a0 * dx + a1 * dx^2 + ... + a6 * dx^7
 // For |dx| < 2^-14:
 //   | output - 10^dx | < 1.5 * 2^-124.
-LIBC_INLINE constexpr Float128 exp10_poly_approx_f128(const Float128 &dx) {
+LIBC_INLINE Float128 exp10_poly_approx_f128(const Float128 &dx) {
   constexpr Float128 COEFFS_128[]{
       {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0
       {Sign::POS, -126, 0x935d8ddd'aaa8ac16'ea56d62b'82d30a2d_u128},
@@ -235,7 +234,7 @@ LIBC_INLINE double exp10_denorm(double x) {
 //  * x >= log10(2^1024)
 //  * x <= log10(2^-1022)
 //  * x is inf or nan
-LIBC_INLINE constexpr double exp10_set_exceptional(double x) {
+LIBC_INLINE double exp10_set_exceptional(double x) {
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
 
@@ -286,7 +285,7 @@ LIBC_INLINE constexpr double exp10_set_exceptional(double x) {
 
 namespace math {
 
-LIBC_INLINE constexpr double exp10(double x) {
+LIBC_INLINE double exp10(double x) {
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
 
diff --git a/libc/src/__support/math/exp10f.h b/libc/src/__support/math/exp10f.h
index 31d3492d56a5e..41f9a73a09935 100644
--- a/libc/src/__support/math/exp10f.h
+++ b/libc/src/__support/math/exp10f.h
@@ -20,7 +20,7 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace math {
 
-LIBC_INLINE constexpr float exp10f(float x) {
+LIBC_INLINE float exp10f(float x) {
   using FPBits = typename fputil::FPBits<float>;
   FPBits xbits(x);
 
diff --git a/libc/src/__support/math/exp10m1f.h b/libc/src/__support/math/exp10m1f.h
index 25cfa13789ebd..c45d3752d6f6c 100644
--- a/libc/src/__support/math/exp10m1f.h
+++ b/libc/src/__support/math/exp10m1f.h
@@ -104,7 +104,7 @@ LIBC_INLINE_VAR constexpr fputil::ExceptValues<float, N_EXCEPTS_HI>
 
 } // namespace exp10m1f_internal
 
-LIBC_INLINE constexpr float exp10m1f(float x) {
+LIBC_INLINE float exp10m1f(float x) {
   using namespace exp10m1f_internal;
   using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
diff --git a/libc/src/__support/math/exp2.h b/libc/src/__support/math/exp2.h
index 9a3e9c6f19dec..1f12347c7103d 100644
--- a/libc/src/__support/math/exp2.h
+++ b/libc/src/__support/math/exp2.h
@@ -77,7 +77,7 @@ LIBC_INLINE double poly_approx_d(double dx) {
 // > P = fpminimax((2^x - 1)/x, 5, [|DD...|], [-2^-13 - 2^-30, 2^-13 + 2^-30]);
 // Error bounds:
 //   | output - 2^(dx) | < 2^-101
-LIBC_INLINE constexpr DoubleDouble poly_approx_dd(const DoubleDouble &dx) {
+LIBC_INLINE DoubleDouble poly_approx_dd(const DoubleDouble &dx) {
   // Taylor polynomial.
   constexpr DoubleDouble COEFFS[] = {
       {0, 0x1p0},
@@ -98,7 +98,7 @@ LIBC_INLINE constexpr DoubleDouble poly_approx_dd(const DoubleDouble &dx) {
 // Return exp(dx) ~ 1 + a0 * dx + a1 * dx^2 + ... + a6 * dx^7
 // For |dx| < 2^-13 + 2^-30:
 //   | output - exp(dx) | < 2^-126.
-LIBC_INLINE constexpr Float128 poly_approx_f128(const Float128 &dx) {
+LIBC_INLINE Float128 poly_approx_f128(const Float128 &dx) {
   constexpr Float128 COEFFS_128[]{
       {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0
       {Sign::POS, -128, 0xb17217f7'd1cf79ab'c9e3b398'03f2f6af_u128},
@@ -119,7 +119,7 @@ LIBC_INLINE constexpr Float128 poly_approx_f128(const Float128 &dx) {
 // Compute 2^(x) using 128-bit precision.
 // TODO(lntue): investigate triple-double precision implementation for this
 // step.
-LIBC_INLINE constexpr Float128 exp2_f128(double x, int hi, int idx1, int idx2) {
+LIBC_INLINE Float128 exp2_f128(double x, int hi, int idx1, int idx2) {
   Float128 dx = Float128(x);
 
   // TODO: Skip recalculating exp_mid1 and exp_mid2.
@@ -213,7 +213,7 @@ LIBC_INLINE double exp2_denorm(double x) {
 //  * x >= 1024
 //  * x <= -1022
 //  * x is inf or nan
-LIBC_INLINE constexpr double set_exceptional(double x) {
+LIBC_INLINE double set_exceptional(double x) {
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
 
@@ -264,7 +264,7 @@ LIBC_INLINE constexpr double set_exceptional(double x) {
 
 } // namespace exp2_internal
 
-LIBC_INLINE constexpr double exp2(double x) {
+LIBC_INLINE double exp2(double x) {
   using namespace exp2_internal;
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
diff --git a/libc/src/__support/math/exp2f.h b/libc/src/__support/math/exp2f.h
index a231fcedda034..439c752969b4d 100644
--- a/libc/src/__support/math/exp2f.h
+++ b/libc/src/__support/math/exp2f.h
@@ -26,7 +26,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float exp2f(float x) {
+LIBC_INLINE float exp2f(float x) {
   using FPBits = typename fputil::FPBits<float>;
   FPBits xbits(x);
 
diff --git a/libc/src/__support/math/exp2m1f.h b/libc/src/__support/math/exp2m1f.h
index f1acde27ac0e1..49cd4589ace85 100644
--- a/libc/src/__support/math/exp2m1f.h
+++ b/libc/src/__support/math/exp2m1f.h
@@ -26,7 +26,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float exp2m1f(float x) {
+LIBC_INLINE float exp2m1f(float x) {
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
   constexpr size_t N_EXCEPTS_LO = 8;
 
diff --git a/libc/src/__support/math/expf.h b/libc/src/__support/math/expf.h
index 5fcf0ffa97d5c..a635c01d22772 100644
--- a/libc/src/__support/math/expf.h
+++ b/libc/src/__support/math/expf.h
@@ -24,7 +24,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float expf(float x) {
+LIBC_INLINE float expf(float x) {
   using FPBits = typename fputil::FPBits<float>;
   FPBits xbits(x);
 
diff --git a/libc/src/__support/math/expm1.h b/libc/src/__support/math/expm1.h
index 2e07e10883547..0e581ea29fcd7 100644
--- a/libc/src/__support/math/expm1.h
+++ b/libc/src/__support/math/expm1.h
@@ -87,7 +87,7 @@ LIBC_INLINE double poly_approx_d(double dx) {
 // Return expm1(dx) / dx ~ 1 + dx / 2 + dx^2 / 6 + ... + dx^6 / 5040
 // For |dx| < 2^-13 + 2^-30:
 //   | output - expm1(dx) | < 2^-101
-LIBC_INLINE constexpr DoubleDouble poly_approx_dd(const DoubleDouble &dx) {
+LIBC_INLINE DoubleDouble poly_approx_dd(const DoubleDouble &dx) {
   // Taylor polynomial.
   constexpr DoubleDouble COEFFS[] = {
       {0, 0x1p0},                                      // 1
@@ -108,8 +108,7 @@ LIBC_INLINE constexpr DoubleDouble poly_approx_dd(const DoubleDouble &dx) {
 // Return (exp(dx) - 1)/dx ~ 1 + dx / 2 + dx^2 / 6 + ... + dx^6 / 5040
 // For |dx| < 2^-13 + 2^-30:
 //   | output - exp(dx) | < 2^-126.
-[[maybe_unused]] LIBC_INLINE constexpr Float128
-poly_approx_f128(const Float128 &dx) {
+[[maybe_unused]] LIBC_INLINE Float128 poly_approx_f128(const Float128 &dx) {
   constexpr Float128 COEFFS_128[]{
       {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0
       {Sign::POS, -128, 0x80000000'00000000'00000000'00000000_u128}, // 0.5
@@ -225,7 +224,7 @@ LIBC_INLINE DoubleDouble exp_double_double(double x, double kd,
 
 // Check for exceptional cases when
 // |x| <= 2^-53 or x < log(2^-54) or x >= 0x1.6232bdd7abcd3p+9
-LIBC_INLINE constexpr double set_exceptional(double x) {
+LIBC_INLINE double set_exceptional(double x) {
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
 
@@ -279,7 +278,7 @@ LIBC_INLINE constexpr double set_exceptional(double x) {
 
 } // namespace expm1_internal
 
-LIBC_INLINE constexpr double expm1(double x) {
+LIBC_INLINE double expm1(double x) {
   using namespace expm1_internal;
 
   using FPBits = typename fputil::FPBits<double>;
diff --git a/libc/src/__support/math/expm1f.h b/libc/src/__support/math/expm1f.h
index f581635f77c7b..60dd62bf7be8d 100644
--- a/libc/src/__support/math/expm1f.h
+++ b/libc/src/__support/math/expm1f.h
@@ -27,7 +27,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float expm1f(float x) {
+LIBC_INLINE float expm1f(float x) {
   using namespace common_constants_internal;
   using FPBits = typename fputil::FPBits<float>;
   FPBits xbits(x);
diff --git a/libc/src/__support/math/fsqrt.h b/libc/src/__support/math/fsqrt.h
index d35f25b9a8111..30fb8f4f5a84b 100644
--- a/libc/src/__support/math/fsqrt.h
+++ b/libc/src/__support/math/fsqrt.h
@@ -15,7 +15,9 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float fsqrt(double x) { return fputil::sqrt<float>(x); }
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT float fsqrt(double x) {
+  return fputil::sqrt<float>(x);
+}
 
 } // namespace math
 
diff --git a/libc/src/__support/math/fsqrtf128.h b/libc/src/__support/math/fsqrtf128.h
index 955e19a818c57..61353c8043dd3 100644
--- a/libc/src/__support/math/fsqrtf128.h
+++ b/libc/src/__support/math/fsqrtf128.h
@@ -21,7 +21,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float fsqrtf128(float128 x) {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT float fsqrtf128(float128 x) {
   return fputil::sqrt<float>(x);
 }
 
diff --git a/libc/src/__support/math/fsqrtl.h b/libc/src/__support/math/fsqrtl.h
index 26c3b9e4c14c9..44b6609b713a4 100644
--- a/libc/src/__support/math/fsqrtl.h
+++ b/libc/src/__support/math/fsqrtl.h
@@ -15,7 +15,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float fsqrtl(long double x) {
+LIBC_INLINE LIBC_CONSTEXPR_DEFAULT float fsqrtl(long double x) {
   return fputil::sqrt<float>(x);
 }
 
diff --git a/libc/src/__support/math/log.h b/libc/src/__support/math/log.h
index 62bdf4e25431e..917d1cc51cbb1 100644
--- a/libc/src/__support/math/log.h
+++ b/libc/src/__support/math/log.h
@@ -721,7 +721,7 @@ LIBC_INLINE_VAR constexpr Float128 BIG_COEFFS[3]{
 // Reuse the output of the fast pass range reduction.
 // -2^-8 <= m_x < 2^-7
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-LIBC_INLINE constexpr double log_accurate(int e_x, int index, double m_x) {
+LIBC_INLINE double log_accurate(int e_x, int index, double m_x) {
   Float128 e_x_f128(static_cast<float>(e_x));
   Float128 sum = fputil::quick_mul(LOG_2, e_x_f128);
   sum = fputil::quick_add(sum, LOG_TABLE.step_1[index]);
diff --git a/libc/src/__support/math/nextafterl.h b/libc/src/__support/math/nextafterl.h
index a173ccfaa4c73..cf2c2e6da5fb4 100644
--- a/libc/src/__support/math/nextafterl.h
+++ b/libc/src/__support/math/nextafterl.h
@@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr long double nextafterl(long double x, long double y) {
+LIBC_INLINE long double nextafterl(long double x, long double y) {
   return fputil::nextafter(x, y);
 }
 
diff --git a/libc/src/__support/math/nextdownl.h b/libc/src/__support/math/nextdownl.h
index 235186d0b2d43..d0a71fe55fb7d 100644
--- a/libc/src/__support/math/nextdownl.h
+++ b/libc/src/__support/math/nextdownl.h
@@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr long double nextdownl(long double x) {
+LIBC_INLINE long double nextdownl(long double x) {
   return fputil::nextupdown</*IsDown=*/true>(x);
 }
 
diff --git a/libc/src/__support/math/nextupl.h b/libc/src/__support/math/nextupl.h
index 2d0e43a3d9f5a..5e2ff41bc8c89 100644
--- a/libc/src/__support/math/nextupl.h
+++ b/libc/src/__support/math/nextupl.h
@@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr long double nextupl(long double x) {
+LIBC_INLINE long double nextupl(long double x) {
   return fputil::nextupdown</*IsDown=*/false>(x);
 }
 
diff --git a/libc/src/__support/math/pow.h b/libc/src/__support/math/pow.h
index 27e382435ecb3..c03e6be271d05 100644
--- a/libc/src/__support/math/pow.h
+++ b/libc/src/__support/math/pow.h
@@ -177,7 +177,7 @@ LIBC_INLINE_VAR constexpr DoubleDouble LOG2_R_DD[128] = {
     {0.0, 1.0},
 };
 
-LIBC_INLINE constexpr bool is_odd_integer(double x) {
+LIBC_INLINE bool is_odd_integer(double x) {
   using FPBits = fputil::FPBits<double>;
   FPBits xbits(x);
   uint64_t x_u = xbits.uintval();
@@ -189,7 +189,7 @@ LIBC_INLINE constexpr bool is_odd_integer(double x) {
   return (x_e + lsb == UNIT_EXPONENT);
 }
 
-LIBC_INLINE constexpr bool is_integer(double x) {
+LIBC_INLINE bool is_integer(double x) {
   using FPBits = fputil::FPBits<double>;
   FPBits xbits(x);
   uint64_t x_u = xbits.uintval();
diff --git a/libc/src/__support/math/powf.h b/libc/src/__support/math/powf.h
index 5762309794d27..7721d0d7f9534 100644
--- a/libc/src/__support/math/powf.h
+++ b/libc/src/__support/math/powf.h
@@ -533,7 +533,7 @@ LIBC_INLINE_VAR constexpr DoubleDouble LOG2_R2_DD[] = {
 };
 #endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
-LIBC_INLINE constexpr bool is_odd_integer(float x) {
+LIBC_INLINE bool is_odd_integer(float x) {
   using FPBits = typename fputil::FPBits<float>;
   uint32_t x_u = cpp::bit_cast<uint32_t>(x);
   int32_t x_e =
@@ -544,7 +544,7 @@ LIBC_INLINE constexpr bool is_odd_integer(float x) {
   return (x_e + lsb == UNIT_EXPONENT);
 }
 
-LIBC_INLINE constexpr bool is_integer(float x) {
+LIBC_INLINE bool is_integer(float x) {
   using FPBits = typename fputil::FPBits<float>;
   uint32_t x_u = cpp::bit_cast<uint32_t>(x);
   int32_t x_e =
@@ -556,7 +556,7 @@ LIBC_INLINE constexpr bool is_integer(float x) {
 }
 
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-LIBC_INLINE constexpr bool larger_exponent(double a, double b) {
+LIBC_INLINE bool larger_exponent(double a, double b) {
   using DoubleBits = typename fputil::FPBits<double>;
   return DoubleBits(a).get_biased_exponent() >=
          DoubleBits(b).get_biased_exponent();
diff --git a/libc/src/__support/math/rsqrtf.h b/libc/src/__support/math/rsqrtf.h
index 1e98a5dbb428f..78606be68cce1 100644
--- a/libc/src/__support/math/rsqrtf.h
+++ b/libc/src/__support/math/rsqrtf.h
@@ -20,7 +20,7 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace math {
 
-LIBC_INLINE constexpr float rsqrtf(float x) {
+LIBC_INLINE float rsqrtf(float x) {
   using FPBits = fputil::FPBits<float>;
   FPBits xbits(x);
 
diff --git a/libc/src/__support/math/sin.h b/libc/src/__support/math/sin.h
index 124df61b1dc80..7f2833e30f135 100644
--- a/libc/src/__support/math/sin.h
+++ b/libc/src/__support/math/sin.h
@@ -29,7 +29,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr double sin(double x) {
+LIBC_INLINE double sin(double x) {
   using namespace math::range_reduction_double_internal;
   using FPBits = typename fputil::FPBits<double>;
   FPBits xbits(x);
diff --git a/libc/src/__support/math/sinhf.h b/libc/src/__support/math/sinhf.h
index 6af34412129fc..141d87ba72bd2 100644
--- a/libc/src/__support/math/sinhf.h
+++ b/libc/src/__support/math/sinhf.h
@@ -20,7 +20,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE constexpr float sinhf(float x) {
+LIBC_INLINE float sinhf(float x) {
   using FPBits = typename fputil::FPBits<float>;
   FPBits xbits(x);
   uint32_t x_abs = xbits.abs().uintval();
diff --git a/libc/src/__support/math/tan.h b/libc/src/__support/math/tan.h
index 27cd4b7a044ab..7717f835dc94d 100644
--- a/libc/src/__support/math/tan.h
+++ b/libc/src/__support/math/tan.h
@@ -111,7 +111,7 @@ LIBC_INLINE double tan_eval(const DoubleDouble &u, DoubleDouble &result) {
 [[maybe_unused]] Float128 newton_raphson_div(const Float128 &a, Float128 b,
                                              double q) {
   Float128 q0(q);
-  constexpr Float128 TWO(2.0);
+  LIBC_BIT_CAST_CONSTEXPR_VAR Float128 TWO(2.0);
   b.sign = (b.sign == Sign::POS) ? Sign::NEG : Sign::POS;
   Float128 q1 =
       fputil::quick_mul(q0, fputil::quick_add(TWO, fputil::quick_mul(b, q0)));

>From 7929f8ac8bdd0dfa7b4d24e249bbaef6e8acfb11 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 04:58:54 +0000
Subject: [PATCH 6/7] Fix or ignore old gcc's warnings.

---
 libc/cmake/modules/CheckCompilerFeatures.cmake      |  5 ++++-
 libc/cmake/modules/LLVMLibCCompileOptionRules.cmake | 11 +++++++++--
 libc/cmake/modules/LLVMLibCTestRules.cmake          |  7 ++++++-
 libc/src/string/memory_utils/utils.h                |  2 ++
 libc/src/string/memory_utils/x86_64/inline_strlen.h | 13 ++++++-------
 libc/test/shared/shared_math_constexpr_test.cpp     |  2 +-
 6 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/libc/cmake/modules/CheckCompilerFeatures.cmake b/libc/cmake/modules/CheckCompilerFeatures.cmake
index cbaa3213f1bf3..325b5efe3f805 100644
--- a/libc/cmake/modules/CheckCompilerFeatures.cmake
+++ b/libc/cmake/modules/CheckCompilerFeatures.cmake
@@ -154,4 +154,7 @@ check_cxx_compiler_flag("-nostdlib++" LIBC_CC_SUPPORTS_NOSTDLIBPP)
 check_cxx_compiler_flag("-nostdlibinc" LIBC_CC_SUPPORTS_NOSTDLIBINC)
 
 # clang-23+, post llvm.org/pr187860
-check_cxx_compiler_flag("-Werror -Wno-fenv-access" LIBC_CC_SUPPORTS_NO_FENV_ACCESS)
+check_cxx_compiler_flag("-Wfenv-access" LIBC_CC_SUPPORTS_NO_FENV_ACCESS)
+
+# clang-all, gcc-8+
+check_cxx_compiler_flag("-Wextra-semi" LIBC_CC_SUPPORTS_EXTRA_SEMI)
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index b8c4ee0801b9d..2ac20590c1819 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -288,7 +288,12 @@ function(_get_common_compile_options output_var flags)
     if(NOT LIBC_WNO_ERROR)
       list(APPEND compile_options "-Werror")
     endif()
-    list(APPEND compile_options "-Wconversion")
+    if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0"))
+      list(APPEND compile_options "-Wconversion")
+    else()
+      list(APPEND compile_options "-Wno-type-limits")
+      list(APPEND compile_options "-Wno-attributes")
+    endif()
     list(APPEND compile_options "-Wno-sign-conversion")
     list(APPEND compile_options "-Wdeprecated")
     if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -301,7 +306,9 @@ function(_get_common_compile_options output_var flags)
     list(APPEND compile_options "-Wno-pedantic")
     list(APPEND compile_options "-Wimplicit-fallthrough")
     list(APPEND compile_options "-Wwrite-strings")
-    list(APPEND compile_options "-Wextra-semi")
+    if(LIBC_CC_SUPPORTS_EXTRA_SEMI)
+      list(APPEND compile_options "-Wextra-semi")
+    endif()
     if(NOT CMAKE_COMPILER_IS_GNUCXX)
       list(APPEND compile_options "-Wnewline-eof")
       list(APPEND compile_options "-Wnonportable-system-include-path")
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index 9faf47f4d3297..39f227464402b 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -44,7 +44,12 @@ function(_get_common_test_compile_options output_var c_test flags)
     if(NOT LIBC_WNO_ERROR)
       # list(APPEND compile_options "-Werror")
     endif()
-    list(APPEND compile_options "-Wconversion")
+    if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0"))
+      list(APPEND compile_options "-Wconversion")
+    else()
+      list(APPEND compile_options "-Wno-type-limits")
+      list(APPEND compile_options "-Wno-attributes")
+    endif()
     # FIXME: convert to -Wsign-conversion
     list(APPEND compile_options "-Wno-sign-conversion")
     list(APPEND compile_options "-Wimplicit-fallthrough")
diff --git a/libc/src/string/memory_utils/utils.h b/libc/src/string/memory_utils/utils.h
index 6f6882b49223b..9824c4b058b3a 100644
--- a/libc/src/string/memory_utils/utils.h
+++ b/libc/src/string/memory_utils/utils.h
@@ -94,7 +94,9 @@ LIBC_INLINE void memcpy_inline(void *__restrict dst,
 #ifndef LIBC_COMPILER_IS_MSVC
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Warray-bounds"
+#if defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 1100)
 #pragma GCC diagnostic ignored "-Wstringop-overread"
+#endif // LIBC_COMPILER_IS_GCC && LIBC_COMPILER_GCC_VER >= 1100
 #pragma GCC diagnostic ignored "-Wstringop-overflow"
 #endif // !LIBC_COMPILER_IS_MSVC
   for (size_t i = 0; i < Size; ++i)
diff --git a/libc/src/string/memory_utils/x86_64/inline_strlen.h b/libc/src/string/memory_utils/x86_64/inline_strlen.h
index 74b6820a50ff1..0343e22f3e58e 100644
--- a/libc/src/string/memory_utils/x86_64/inline_strlen.h
+++ b/libc/src/string/memory_utils/x86_64/inline_strlen.h
@@ -24,20 +24,20 @@ LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE static Mask
 compare_and_mask(const Vector *block_ptr, char c);
 
 template <typename Vector, typename Mask,
-          decltype(compare_and_mask<Vector, Mask>)>
+          Mask (*CompareAndMask)(const Vector *, char)>
 LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE static size_t
 string_length_vector(const char *src) {
   uintptr_t misalign_bytes = reinterpret_cast<uintptr_t>(src) % sizeof(Vector);
 
   const Vector *block_ptr =
       reinterpret_cast<const Vector *>(src - misalign_bytes);
-  auto cmp = compare_and_mask<Vector, Mask>(block_ptr, 0) >> misalign_bytes;
+  auto cmp = CompareAndMask(block_ptr, 0) >> misalign_bytes;
   if (cmp)
     return cpp::countr_zero(cmp);
 
   while (true) {
     block_ptr++;
-    cmp = compare_and_mask<Vector, Mask>(block_ptr, 0);
+    cmp = CompareAndMask(block_ptr, 0);
     if (cmp)
       return static_cast<size_t>(reinterpret_cast<uintptr_t>(block_ptr) -
                                  reinterpret_cast<uintptr_t>(src) +
@@ -56,15 +56,14 @@ calculate_find_first_character_return(const unsigned char *src, Mask c_mask,
 }
 
 template <typename Vector, typename Mask,
-          decltype(compare_and_mask<Vector, Mask>)>
+          Mask (*CompareAndMask)(const Vector *, char)>
 LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE static void *
 find_first_character_vector(const unsigned char *s, unsigned char c, size_t n) {
   uintptr_t misalign_bytes = reinterpret_cast<uintptr_t>(s) % sizeof(Vector);
 
   const Vector *block_ptr =
       reinterpret_cast<const Vector *>(s - misalign_bytes);
-  auto cmp_bytes =
-      compare_and_mask<Vector, Mask>(block_ptr, c) >> misalign_bytes;
+  auto cmp_bytes = CompareAndMask(block_ptr, c) >> misalign_bytes;
   if (cmp_bytes)
     return calculate_find_first_character_return<Mask>(
         reinterpret_cast<const unsigned char *>(block_ptr) + misalign_bytes,
@@ -73,7 +72,7 @@ find_first_character_vector(const unsigned char *s, unsigned char c, size_t n) {
   for (size_t bytes_checked = sizeof(Vector) - misalign_bytes;
        bytes_checked < n; bytes_checked += sizeof(Vector)) {
     block_ptr++;
-    cmp_bytes = compare_and_mask<Vector, Mask>(block_ptr, c);
+    cmp_bytes = CompareAndMask(block_ptr, c);
     if (cmp_bytes)
       return calculate_find_first_character_return<Mask>(
           reinterpret_cast<const unsigned char *>(block_ptr), cmp_bytes,
diff --git a/libc/test/shared/shared_math_constexpr_test.cpp b/libc/test/shared/shared_math_constexpr_test.cpp
index 1e7ccb623fc55..821042e1dab92 100644
--- a/libc/test/shared/shared_math_constexpr_test.cpp
+++ b/libc/test/shared/shared_math_constexpr_test.cpp
@@ -258,7 +258,7 @@ static_assert(0 == [] {
   float16 setpayload_x = 0.0f16;
   return LIBC_NAMESPACE::shared::setpayloadf16(&setpayload_x, 0.0f16);
 }());
-static_assert(0LL == LIBC_NAMESPACE::shared::llrintf16(0.0));
+static_assert(0LL == LIBC_NAMESPACE::shared::llrintf16(0.0f16));
 static_assert(0LL == LIBC_NAMESPACE::shared::llroundf16(0.0f16));
 static_assert(0L == LIBC_NAMESPACE::shared::lrintf16(0.0f16));
 static_assert(0L == LIBC_NAMESPACE::shared::lroundf16(0.0f16));

>From 5d27ec3bf1d2f63c871385a41b764f68d9d9cf63 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 21 May 2026 13:54:23 +0000
Subject: [PATCH 7/7] Update NormalFloat constexpr annotations.

---
 libc/src/__support/FPUtil/NormalFloat.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h
index 2da317a356405..f7d32073c74a9 100644
--- a/libc/src/__support/FPUtil/NormalFloat.h
+++ b/libc/src/__support/FPUtil/NormalFloat.h
@@ -95,7 +95,7 @@ template <typename T> struct NormalFloat {
     return result;
   }
 
-  LIBC_INLINE operator T() const {
+  LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR operator T() const {
     int biased_exponent = exponent + FPBits<T>::EXP_BIAS;
     // Max exponent is of the form 0xFF...E. That is why -2 and not -1.
     constexpr int MAX_EXPONENT_VALUE = (1 << FPBits<T>::EXP_LEN) - 2;
@@ -216,7 +216,9 @@ NormalFloat<long double>::init_from_bits(FPBits<long double> bits) {
   }
 }
 
-template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {
+template <>
+LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR NormalFloat<long double>::
+operator long double() const {
   using LDBits = FPBits<long double>;
   int biased_exponent = exponent + LDBits::EXP_BIAS;
   // Max exponent is of the form 0xFF...E. That is why -2 and not -1.



More information about the libc-commits mailing list