[libc-commits] [libc] [llvm] [libc][math] Move hypot to shared/math and make it constexpr (PR #177588)
Chinmay Ingle via libc-commits
libc-commits at lists.llvm.org
Tue Feb 10 12:01:38 PST 2026
https://github.com/chinmayingle updated https://github.com/llvm/llvm-project/pull/177588
>From 4c11d247882c6d625a3b8627aa8fea3dead34205 Mon Sep 17 00:00:00 2001
From: chinmayingle <chinmay.r.ingle at gmail.com>
Date: Fri, 23 Jan 2026 19:08:00 +0530
Subject: [PATCH 1/2] [libc][math] Move hypot to shared/math and make it
constexpr
---
libc/shared/math.h | 1 +
libc/shared/math/hypot.h | 14 ++
libc/src/__support/math/CMakeLists.txt | 15 ++
libc/src/__support/math/hypot.h | 219 ++++++++++++++++++
libc/src/math/generic/CMakeLists.txt | 3 +-
libc/src/math/generic/hypot.cpp | 10 +-
libc/test/shared/CMakeLists.txt | 1 +
libc/test/shared/shared_math_test.cpp | 22 ++
.../llvm-project-overlay/libc/BUILD.bazel | 15 ++
9 files changed, 295 insertions(+), 5 deletions(-)
create mode 100644 libc/shared/math/hypot.h
create mode 100644 libc/src/__support/math/hypot.h
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 66132326c2257..7e222310560e3 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -72,6 +72,7 @@
#include "math/fsqrt.h"
#include "math/fsqrtf128.h"
#include "math/fsqrtl.h"
+#include "math/hypot.h"
#include "math/hypotf.h"
#include "math/ilogb.h"
#include "math/ilogbf.h"
diff --git a/libc/shared/math/hypot.h b/libc/shared/math/hypot.h
new file mode 100644
index 0000000000000..383420fa3efd5
--- /dev/null
+++ b/libc/shared/math/hypot.h
@@ -0,0 +1,14 @@
+// libc/src/math/hypot.h
+#ifndef LLVM_LIBC_SRC_MATH_HYPOT_H
+#define LLVM_LIBC_SRC_MATH_HYPOT_H
+
+// #include "src/__support/macros/config.h"
+#include "src/__support/math/hypot.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// double hypot(double x, double y);
+using math::hypot;
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_HYPOT_H
\ No newline at end of file
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index c0293c0969217..1de6a405da13b 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -1124,6 +1124,21 @@ add_header_library(
libc.src.__support.macros.optimization
)
+add_header_library(
+ hypot
+ HDRS
+ hypot.h
+ DEPENDS
+ libc.src.__support.common
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.rounding_mode
+ libc.src.__support.FPUtil.basic_operations
+ libc.src.__support.CPP.type_traits
+ libc.src.__support.CPP.bit
+ libc.src.__support.uint128
+)
+
add_header_library(
ilogbl
HDRS
diff --git a/libc/src/__support/math/hypot.h b/libc/src/__support/math/hypot.h
new file mode 100644
index 0000000000000..355ee0a29f8d6
--- /dev/null
+++ b/libc/src/__support/math/hypot.h
@@ -0,0 +1,219 @@
+//===-- Implementation header for hypot -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_MATH_HYPOT_H
+#define LLVM_LIBC_SRC_SUPPORT_MATH_HYPOT_H
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/FPUtil/BasicOperations.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/uint128.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace math {
+
+namespace internal {
+// Helper to find the leading one in a mantissa.
+template <typename T>
+LIBC_INLINE constexpr T find_leading_one(T mant, int &shift_length) {
+ shift_length = 0;
+ if (mant > 0) {
+ shift_length = (sizeof(mant) * 8) - 1 - cpp::countl_zero(mant);
+ }
+ return static_cast<T>((T(1) << shift_length));
+}
+
+// DoubleLength structure mapping
+template <typename T> struct DoubleLength;
+template <> struct DoubleLength<uint16_t> { using Type = uint32_t; };
+template <> struct DoubleLength<uint32_t> { using Type = uint64_t; };
+template <> struct DoubleLength<uint64_t> { using Type = UInt128; };
+
+} // namespace internal
+
+// Correctly rounded IEEE 754 HYPOT(x, y) with round to nearest, ties to even.
+LIBC_INLINE constexpr double hypot(double x, double y) {
+ using FPBits_t = fputil::FPBits<double>;
+ using StorageType = FPBits_t::StorageType;
+ using DStorageType = internal::DoubleLength<StorageType>::Type;
+
+ FPBits_t x_bits(x);
+ FPBits_t y_bits(y);
+
+ FPBits_t x_abs = x_bits.abs();
+ FPBits_t y_abs = y_bits.abs();
+
+ bool x_abs_larger = x_abs.uintval() >= y_abs.uintval();
+
+ FPBits_t a_bits = x_abs_larger ? x_abs : y_abs;
+ FPBits_t b_bits = x_abs_larger ? y_abs : x_abs;
+
+ // 1. Handle Special Cases (Inf / NaN)
+ if (LIBC_UNLIKELY(a_bits.is_inf_or_nan())) {
+ if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) {
+ if (!cpp::is_constant_evaluated())
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits_t::quiet_nan().get_val();
+ }
+ if (x_abs.is_inf() || y_abs.is_inf())
+ return FPBits_t::inf().get_val();
+ if (x_abs.is_nan())
+ return x;
+ return y; // y is nan
+ }
+
+ uint16_t a_exp = a_bits.get_biased_exponent();
+ uint16_t b_exp = b_bits.get_biased_exponent();
+
+ // 2. Trivial Case
+ if ((a_exp - b_exp >= FPBits_t::FRACTION_LEN + 2) || (x == 0) || (y == 0)) {
+ return x_abs.get_val() + y_abs.get_val();
+ }
+
+ // 3. Setup Soft-Float Arithmetic
+ uint64_t out_exp = a_exp;
+ StorageType a_mant = a_bits.get_mantissa();
+ StorageType b_mant = b_bits.get_mantissa();
+
+ // FIXED: Initialized variables for constexpr
+ DStorageType a_mant_sq = 0;
+ DStorageType b_mant_sq = 0;
+ bool sticky_bits = false;
+
+ constexpr StorageType ONE = StorageType(1) << (FPBits_t::FRACTION_LEN + 1);
+
+ a_mant <<= 1;
+ b_mant <<= 1;
+
+ // FIXED: Initialized variables for constexpr
+ StorageType leading_one = 0;
+ int y_mant_width = 0;
+
+ if (a_exp != 0) {
+ leading_one = ONE;
+ a_mant |= ONE;
+ y_mant_width = FPBits_t::FRACTION_LEN + 1;
+ } else {
+ leading_one = internal::find_leading_one(a_mant, y_mant_width);
+ a_exp = 1;
+ }
+
+ if (b_exp != 0)
+ b_mant |= ONE;
+ else
+ b_exp = 1;
+
+ a_mant_sq = static_cast<DStorageType>(a_mant) * a_mant;
+ b_mant_sq = static_cast<DStorageType>(b_mant) * b_mant;
+
+ // 4. Align and Add
+ uint16_t shift_length = static_cast<uint16_t>(2 * (a_exp - b_exp));
+ sticky_bits =
+ ((b_mant_sq & ((DStorageType(1) << shift_length) - DStorageType(1))) !=
+ DStorageType(0));
+ b_mant_sq >>= shift_length;
+
+ DStorageType sum = a_mant_sq + b_mant_sq;
+
+ // 5. Normalize Sum
+ if (sum >= (DStorageType(1) << (2 * y_mant_width + 2))) {
+ if (leading_one == ONE) {
+ sticky_bits = sticky_bits || ((sum & 0x3U) != 0);
+ sum >>= 2;
+ ++out_exp;
+
+ if (out_exp >= FPBits_t::MAX_BIASED_EXPONENT) {
+ if (!cpp::is_constant_evaluated()) {
+ int round_mode = fputil::quick_get_round();
+ if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
+ return FPBits_t::inf().get_val();
+ } else {
+ return FPBits_t::inf().get_val();
+ }
+ return FPBits_t::max_normal().get_val();
+ }
+ } else {
+ leading_one <<= 1;
+ ++y_mant_width;
+ }
+ }
+
+ // 6. Digit-by-Digit Sqrt
+ StorageType y_new = leading_one;
+ StorageType r = static_cast<StorageType>(sum >> y_mant_width) - leading_one;
+ StorageType tail_bits = static_cast<StorageType>(sum) & (leading_one - 1);
+
+ for (StorageType current_bit = leading_one >> 1; current_bit;
+ current_bit >>= 1) {
+ r = static_cast<StorageType>((r << 1)) +
+ ((tail_bits & current_bit) ? 1 : 0);
+ StorageType tmp = static_cast<StorageType>((y_new << 1)) +
+ current_bit;
+ if (r >= tmp) {
+ r -= tmp;
+ y_new += current_bit;
+ }
+ }
+
+ bool round_bit = y_new & StorageType(1);
+ bool lsb = y_new & StorageType(2);
+
+ if (y_new >= ONE) {
+ y_new -= ONE;
+ if (out_exp == 0) out_exp = 1;
+ }
+
+ y_new >>= 1;
+
+ // 7. Rounding
+ int round_mode = FE_TONEAREST;
+ if (!cpp::is_constant_evaluated()) {
+ round_mode = fputil::quick_get_round();
+ }
+
+ switch (round_mode) {
+ case FE_TONEAREST:
+ if (round_bit && (lsb || sticky_bits || (r != 0)))
+ ++y_new;
+ break;
+ case FE_UPWARD:
+ if (round_bit || sticky_bits || (r != 0))
+ ++y_new;
+ break;
+ }
+
+ if (y_new >= (ONE >> 1)) {
+ y_new -= ONE >> 1;
+ ++out_exp;
+ if (out_exp >= FPBits_t::MAX_BIASED_EXPONENT) {
+ if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
+ return FPBits_t::inf().get_val();
+ return FPBits_t::max_normal().get_val();
+ }
+ }
+
+ y_new |= static_cast<StorageType>(out_exp) << FPBits_t::FRACTION_LEN;
+
+ if (!cpp::is_constant_evaluated()) {
+ if (!(round_bit || sticky_bits || (r != 0)))
+ fputil::clear_except_if_required(FE_INEXACT);
+ }
+
+ return cpp::bit_cast<double>(y_new);
+}
+
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SUPPORT_MATH_HYPOT_H
\ No newline at end of file
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 96dc0e7ca4851..0d26d01d09711 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3324,7 +3324,8 @@ add_entrypoint_object(
HDRS
../hypot.h
DEPENDS
- libc.src.__support.FPUtil.hypot
+ libc.src.__support.math.hypot
+ libc.src.__support.FPUtil.fp_bits
)
add_entrypoint_object(
diff --git a/libc/src/math/generic/hypot.cpp b/libc/src/math/generic/hypot.cpp
index 0dfe4360bafe0..8ee97d36f9e8a 100644
--- a/libc/src/math/generic/hypot.cpp
+++ b/libc/src/math/generic/hypot.cpp
@@ -7,14 +7,16 @@
//===----------------------------------------------------------------------===//
#include "src/math/hypot.h"
-#include "src/__support/FPUtil/Hypot.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
+#include "src/__support/math/hypot.h"
+// #include "src/__support/FPUtil/Hypot.h"
+// #include "src/__support/common.h"
+// #include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(double, hypot, (double x, double y)) {
- return LIBC_NAMESPACE::fputil::hypot(x, y);
+ return math::hypot(x, y);
+ // return LIBC_NAMESPACE::fputil::hypot(x, y);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 7d72ced3e057c..f518d2b392bcf 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -68,6 +68,7 @@ add_fp_unittest(
libc.src.__support.math.fsqrt
libc.src.__support.math.fsqrtf128
libc.src.__support.math.fsqrtl
+ libc.src.__support.math.hypot
libc.src.__support.math.hypotf
libc.src.__support.math.ilogb
libc.src.__support.math.ilogbf
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 9e024387efbfa..921fa4a437db1 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -120,6 +120,28 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::shared::tanf(0.0f));
}
+// Add this AFTER the AllFloat test block
+TEST(LlvmLibcSharedMathTest, Hypot) {
+ // 1. Basic Pythagorean triples (Runtime check)
+ // We use EXPECT_FP_EQ for safe floating-point comparison
+ EXPECT_FP_EQ(5.0, LIBC_NAMESPACE::math::hypot(3.0, 4.0));
+ EXPECT_FP_EQ(13.0, LIBC_NAMESPACE::math::hypot(5.0, 12.0));
+
+ // 2. Compile-time check (Constexpr)
+ // This verifies your "header-only" logic works at compile time
+ constexpr double result = LIBC_NAMESPACE::math::hypot(3.0, 4.0);
+ static_assert(result == 5.0, "Constexpr hypot failed");
+
+ // 3. Special values (Inf/NaN)
+ constexpr double inf = __builtin_inf();
+ constexpr double nan = __builtin_nan("");
+
+ // Use EXPECT_NE(..., 0) because __builtin functions return int, not bool
+ EXPECT_NE(__builtin_isinf(LIBC_NAMESPACE::math::hypot(inf, 1.0)), 0);
+ EXPECT_NE(__builtin_isinf(LIBC_NAMESPACE::math::hypot(1.0, inf)), 0);
+ EXPECT_NE(__builtin_isnan(LIBC_NAMESPACE::math::hypot(nan, 1.0)), 0);
+}
+
TEST(LlvmLibcSharedMathTest, AllDouble) {
EXPECT_FP_EQ(0x1.921fb54442d18p+0, LIBC_NAMESPACE::shared::acos(0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::asin(0.0));
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 3eae5e4a05b51..4deaaf4a97566 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3770,6 +3770,21 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "src___support_math_hypot",
+ hdrs = ["src/__support/math/hypot.h"],
+ deps = [
+ ":src___support_common",
+ ":src___support_cpp_bit",
+ ":src___support_cpp_type_traits",
+ ":src___support_fp_util_basic_operations",
+ ":src___support_fp_util_fenv_impl",
+ ":src___support_fp_util_fp_bits",
+ ":src___support_fp_util_rounding_mode",
+ ":src___support_uint128",
+ ],
+)
+
############################### complex targets ################################
libc_function(
>From 97417137a39a43a83328fe5140ffb6bd79bab0a6 Mon Sep 17 00:00:00 2001
From: chinmayingle <chinmay.r.ingle at gmail.com>
Date: Tue, 27 Jan 2026 13:00:55 +0530
Subject: [PATCH 2/2] Address review comments
---
libc/shared/math/hypot.h | 20 +-
libc/src/__support/math/CMakeLists.txt | 9 +-
libc/src/__support/math/hypot.h | 209 +-----------------
libc/src/math/generic/CMakeLists.txt | 1 -
libc/src/math/generic/hypot.cpp | 4 -
libc/test/shared/shared_math_test.cpp | 23 +-
.../llvm-project-overlay/libc/BUILD.bazel | 24 +-
7 files changed, 35 insertions(+), 255 deletions(-)
diff --git a/libc/shared/math/hypot.h b/libc/shared/math/hypot.h
index 383420fa3efd5..51fd006397c02 100644
--- a/libc/shared/math/hypot.h
+++ b/libc/shared/math/hypot.h
@@ -1,14 +1,22 @@
-// libc/src/math/hypot.h
-#ifndef LLVM_LIBC_SRC_MATH_HYPOT_H
-#define LLVM_LIBC_SRC_MATH_HYPOT_H
+//===-- Shared hypot function -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SHARED_MATH_HYPOT_H
+#define LLVM_LIBC_SHARED_MATH_HYPOT_H
-// #include "src/__support/macros/config.h"
#include "src/__support/math/hypot.h"
namespace LIBC_NAMESPACE_DECL {
+namespace shared {
-// double hypot(double x, double y);
using math::hypot;
+
+} // namespace shared
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_MATH_HYPOT_H
\ No newline at end of file
+#endif // LLVM_LIBC_SHARED_MATH_HYPOT_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 1de6a405da13b..3da0387751dbb 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -1130,13 +1130,8 @@ add_header_library(
hypot.h
DEPENDS
libc.src.__support.common
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.rounding_mode
- libc.src.__support.FPUtil.basic_operations
- libc.src.__support.CPP.type_traits
- libc.src.__support.CPP.bit
- libc.src.__support.uint128
+ libc.src.__support.macros.config
+ libc.src.__support.FPUtil.hypot
)
add_header_library(
diff --git a/libc/src/__support/math/hypot.h b/libc/src/__support/math/hypot.h
index 355ee0a29f8d6..2b4200ab96034 100644
--- a/libc/src/__support/math/hypot.h
+++ b/libc/src/__support/math/hypot.h
@@ -1,4 +1,5 @@
-//===-- Implementation header for hypot -------------------------*- C++ -*-===//
+//===-- Implementation header for hypot --------------------------*- C++
+//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,214 +7,22 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SUPPORT_MATH_HYPOT_H
-#define LLVM_LIBC_SRC_SUPPORT_MATH_HYPOT_H
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_HYPOT_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_HYPOT_H
-#include "src/__support/CPP/bit.h"
-#include "src/__support/CPP/type_traits.h"
-#include "src/__support/FPUtil/BasicOperations.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/rounding_mode.h"
+#include "src/__support/FPUtil/Hypot.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h"
-#include "src/__support/uint128.h"
namespace LIBC_NAMESPACE_DECL {
-namespace math {
-
-namespace internal {
-// Helper to find the leading one in a mantissa.
-template <typename T>
-LIBC_INLINE constexpr T find_leading_one(T mant, int &shift_length) {
- shift_length = 0;
- if (mant > 0) {
- shift_length = (sizeof(mant) * 8) - 1 - cpp::countl_zero(mant);
- }
- return static_cast<T>((T(1) << shift_length));
-}
-
-// DoubleLength structure mapping
-template <typename T> struct DoubleLength;
-template <> struct DoubleLength<uint16_t> { using Type = uint32_t; };
-template <> struct DoubleLength<uint32_t> { using Type = uint64_t; };
-template <> struct DoubleLength<uint64_t> { using Type = UInt128; };
-
-} // namespace internal
-
-// Correctly rounded IEEE 754 HYPOT(x, y) with round to nearest, ties to even.
-LIBC_INLINE constexpr double hypot(double x, double y) {
- using FPBits_t = fputil::FPBits<double>;
- using StorageType = FPBits_t::StorageType;
- using DStorageType = internal::DoubleLength<StorageType>::Type;
-
- FPBits_t x_bits(x);
- FPBits_t y_bits(y);
-
- FPBits_t x_abs = x_bits.abs();
- FPBits_t y_abs = y_bits.abs();
-
- bool x_abs_larger = x_abs.uintval() >= y_abs.uintval();
-
- FPBits_t a_bits = x_abs_larger ? x_abs : y_abs;
- FPBits_t b_bits = x_abs_larger ? y_abs : x_abs;
-
- // 1. Handle Special Cases (Inf / NaN)
- if (LIBC_UNLIKELY(a_bits.is_inf_or_nan())) {
- if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) {
- if (!cpp::is_constant_evaluated())
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits_t::quiet_nan().get_val();
- }
- if (x_abs.is_inf() || y_abs.is_inf())
- return FPBits_t::inf().get_val();
- if (x_abs.is_nan())
- return x;
- return y; // y is nan
- }
-
- uint16_t a_exp = a_bits.get_biased_exponent();
- uint16_t b_exp = b_bits.get_biased_exponent();
-
- // 2. Trivial Case
- if ((a_exp - b_exp >= FPBits_t::FRACTION_LEN + 2) || (x == 0) || (y == 0)) {
- return x_abs.get_val() + y_abs.get_val();
- }
-
- // 3. Setup Soft-Float Arithmetic
- uint64_t out_exp = a_exp;
- StorageType a_mant = a_bits.get_mantissa();
- StorageType b_mant = b_bits.get_mantissa();
-
- // FIXED: Initialized variables for constexpr
- DStorageType a_mant_sq = 0;
- DStorageType b_mant_sq = 0;
- bool sticky_bits = false;
-
- constexpr StorageType ONE = StorageType(1) << (FPBits_t::FRACTION_LEN + 1);
-
- a_mant <<= 1;
- b_mant <<= 1;
-
- // FIXED: Initialized variables for constexpr
- StorageType leading_one = 0;
- int y_mant_width = 0;
-
- if (a_exp != 0) {
- leading_one = ONE;
- a_mant |= ONE;
- y_mant_width = FPBits_t::FRACTION_LEN + 1;
- } else {
- leading_one = internal::find_leading_one(a_mant, y_mant_width);
- a_exp = 1;
- }
- if (b_exp != 0)
- b_mant |= ONE;
- else
- b_exp = 1;
-
- a_mant_sq = static_cast<DStorageType>(a_mant) * a_mant;
- b_mant_sq = static_cast<DStorageType>(b_mant) * b_mant;
-
- // 4. Align and Add
- uint16_t shift_length = static_cast<uint16_t>(2 * (a_exp - b_exp));
- sticky_bits =
- ((b_mant_sq & ((DStorageType(1) << shift_length) - DStorageType(1))) !=
- DStorageType(0));
- b_mant_sq >>= shift_length;
-
- DStorageType sum = a_mant_sq + b_mant_sq;
-
- // 5. Normalize Sum
- if (sum >= (DStorageType(1) << (2 * y_mant_width + 2))) {
- if (leading_one == ONE) {
- sticky_bits = sticky_bits || ((sum & 0x3U) != 0);
- sum >>= 2;
- ++out_exp;
-
- if (out_exp >= FPBits_t::MAX_BIASED_EXPONENT) {
- if (!cpp::is_constant_evaluated()) {
- int round_mode = fputil::quick_get_round();
- if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
- return FPBits_t::inf().get_val();
- } else {
- return FPBits_t::inf().get_val();
- }
- return FPBits_t::max_normal().get_val();
- }
- } else {
- leading_one <<= 1;
- ++y_mant_width;
- }
- }
-
- // 6. Digit-by-Digit Sqrt
- StorageType y_new = leading_one;
- StorageType r = static_cast<StorageType>(sum >> y_mant_width) - leading_one;
- StorageType tail_bits = static_cast<StorageType>(sum) & (leading_one - 1);
-
- for (StorageType current_bit = leading_one >> 1; current_bit;
- current_bit >>= 1) {
- r = static_cast<StorageType>((r << 1)) +
- ((tail_bits & current_bit) ? 1 : 0);
- StorageType tmp = static_cast<StorageType>((y_new << 1)) +
- current_bit;
- if (r >= tmp) {
- r -= tmp;
- y_new += current_bit;
- }
- }
-
- bool round_bit = y_new & StorageType(1);
- bool lsb = y_new & StorageType(2);
-
- if (y_new >= ONE) {
- y_new -= ONE;
- if (out_exp == 0) out_exp = 1;
- }
-
- y_new >>= 1;
-
- // 7. Rounding
- int round_mode = FE_TONEAREST;
- if (!cpp::is_constant_evaluated()) {
- round_mode = fputil::quick_get_round();
- }
-
- switch (round_mode) {
- case FE_TONEAREST:
- if (round_bit && (lsb || sticky_bits || (r != 0)))
- ++y_new;
- break;
- case FE_UPWARD:
- if (round_bit || sticky_bits || (r != 0))
- ++y_new;
- break;
- }
-
- if (y_new >= (ONE >> 1)) {
- y_new -= ONE >> 1;
- ++out_exp;
- if (out_exp >= FPBits_t::MAX_BIASED_EXPONENT) {
- if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
- return FPBits_t::inf().get_val();
- return FPBits_t::max_normal().get_val();
- }
- }
-
- y_new |= static_cast<StorageType>(out_exp) << FPBits_t::FRACTION_LEN;
-
- if (!cpp::is_constant_evaluated()) {
- if (!(round_bit || sticky_bits || (r != 0)))
- fputil::clear_except_if_required(FE_INEXACT);
- }
+namespace math {
- return cpp::bit_cast<double>(y_new);
+LIBC_INLINE double hypot(double x, double y) {
+ return fputil::hypot(x, y);
}
} // namespace math
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SUPPORT_MATH_HYPOT_H
\ No newline at end of file
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_HYPOT_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 0d26d01d09711..220d969a8850a 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3325,7 +3325,6 @@ add_entrypoint_object(
../hypot.h
DEPENDS
libc.src.__support.math.hypot
- libc.src.__support.FPUtil.fp_bits
)
add_entrypoint_object(
diff --git a/libc/src/math/generic/hypot.cpp b/libc/src/math/generic/hypot.cpp
index 8ee97d36f9e8a..d53a1428177ba 100644
--- a/libc/src/math/generic/hypot.cpp
+++ b/libc/src/math/generic/hypot.cpp
@@ -8,15 +8,11 @@
#include "src/math/hypot.h"
#include "src/__support/math/hypot.h"
-// #include "src/__support/FPUtil/Hypot.h"
-// #include "src/__support/common.h"
-// #include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(double, hypot, (double x, double y)) {
return math::hypot(x, y);
- // return LIBC_NAMESPACE::fputil::hypot(x, y);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 921fa4a437db1..bafbb50b3dd0e 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -120,28 +120,6 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::shared::tanf(0.0f));
}
-// Add this AFTER the AllFloat test block
-TEST(LlvmLibcSharedMathTest, Hypot) {
- // 1. Basic Pythagorean triples (Runtime check)
- // We use EXPECT_FP_EQ for safe floating-point comparison
- EXPECT_FP_EQ(5.0, LIBC_NAMESPACE::math::hypot(3.0, 4.0));
- EXPECT_FP_EQ(13.0, LIBC_NAMESPACE::math::hypot(5.0, 12.0));
-
- // 2. Compile-time check (Constexpr)
- // This verifies your "header-only" logic works at compile time
- constexpr double result = LIBC_NAMESPACE::math::hypot(3.0, 4.0);
- static_assert(result == 5.0, "Constexpr hypot failed");
-
- // 3. Special values (Inf/NaN)
- constexpr double inf = __builtin_inf();
- constexpr double nan = __builtin_nan("");
-
- // Use EXPECT_NE(..., 0) because __builtin functions return int, not bool
- EXPECT_NE(__builtin_isinf(LIBC_NAMESPACE::math::hypot(inf, 1.0)), 0);
- EXPECT_NE(__builtin_isinf(LIBC_NAMESPACE::math::hypot(1.0, inf)), 0);
- EXPECT_NE(__builtin_isnan(LIBC_NAMESPACE::math::hypot(nan, 1.0)), 0);
-}
-
TEST(LlvmLibcSharedMathTest, AllDouble) {
EXPECT_FP_EQ(0x1.921fb54442d18p+0, LIBC_NAMESPACE::shared::acos(0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::asin(0.0));
@@ -154,6 +132,7 @@ TEST(LlvmLibcSharedMathTest, AllDouble) {
EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp2(0.0));
EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp10(0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::expm1(0.0));
+ EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::shared::hypot(0.0, 0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::fsqrt(0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::log(1.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::log10(1.0));
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 4deaaf4a97566..9ee07ebc0db64 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3714,6 +3714,15 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "___support_math_hypot",
+ hdrs = ["src/__support/math/hypot.h"],
+ deps = [
+ ":___support_common",
+ ":___support_fputil_hypot",
+ ],
+)
+
libc_support_library(
name = "__support_math_sinhf",
hdrs = ["src/__support/math/sinhf.h"],
@@ -3770,21 +3779,6 @@ libc_support_library(
],
)
-libc_support_library(
- name = "src___support_math_hypot",
- hdrs = ["src/__support/math/hypot.h"],
- deps = [
- ":src___support_common",
- ":src___support_cpp_bit",
- ":src___support_cpp_type_traits",
- ":src___support_fp_util_basic_operations",
- ":src___support_fp_util_fenv_impl",
- ":src___support_fp_util_fp_bits",
- ":src___support_fp_util_rounding_mode",
- ":src___support_uint128",
- ],
-)
-
############################### complex targets ################################
libc_function(
More information about the libc-commits
mailing list